AS3:如何通过"object"

AS3: how to pass by "object"

我实际上是在寻找一种在 AS3 中通过引用传递的方法,但后来发现 adobe 和很多人对通过引用传递的理解与我在大学里学到的不同。我被教导 java 是按值传递,而 C++ 允许按引用传递。

我并不是要争论什么是值传递和引用传递。我只想解释为什么我在问题中使用对象传递...

回到问题,我想做这样的事情:

public function swapCard(cardA:Cards, cardB:Cards) {
    var temp:Cards = cardA;
    cardA = cardB;
    cardB = temp;
}

...

swapCard(c1, c2);

编辑:添加两个关于我如何使用 swapCard 函数的例子

1) player1和player2手牌交换过程中

swapCard(player1.hand[s], player2.hand[t]);

2) player1的手牌和牌组换牌的过程中

swapCard(player1.hand[s], player1.deck[rand]);

在C++中,我们只需要在参数前加一个符号就可以了(我们称THIS为引用传递)。但在 AS3 中,cardA 和 cardB 只是指向形参的指针。在函数中,更改指针不会对形式参数做任何事情:(

我已经搜索了几个小时,但在不知道卡片的所有属性的情况下找不到方法。

如果我必须一张一张地更改卡片的属性,那么也许我应该将 swapCard 更改为 class Cards 中的静态函数? (因为我不想将所有内容都暴露给另一个 class)我也不确定这是否是一个好的做法。这就像在 class Cars 中添加一个 swap_cars 函数。如果我让这一切发生,接下来会发生什么?洗车、借车、租车……我真的很想保持卡片 class 干净,只保留卡片的详细信息。有没有可能在 AS3 中正确执行此操作?

您尝试实现的 swap 功能在 AS3 中是不可能的。输入参数是对输入对象的引用,但引用本身是按值传递的。这意味着您可以在函数内部更改 cardAcardB,但这些更改在函数外部不可见。

编辑:我在您使用示例用法编辑问题后添加了这一部分。

您似乎在尝试在每个给定的数组位置处交换 2 个不同数组中的两个对象 - 您可以在 AS3 中为此创建一个函数,但不是您尝试的方式。

一种可能的实现方式是传递数组本身以及您要交换的位置;像这样:

// Assumes arrays and indices are correct.
public function SwapCards(playerHand:Array, playerCardIndex:int,
    playerDeck:Array, playerDeckIndex:int):void
{
    var tempCard:Card = playerHand[playerHandIndex];

    playerHand[playerHandIndex] = playerDeck[playerDeckIndex];
    playerDeck[playerDeckIndex] = tempCard;
}

请注意,您仍然交换引用并且数组本身仍然通过引用传递(并且数组引用通过值传递 - 如果您愿意,您可以在此函数内将数组更改为新数组,但您不会'外面看不到新阵列)。但是,由于数组参数在函数内外引用相同的数组,您 可以 更改数组的 contents (或其他数组属性)并且这些更改在外部可见。

此解决方案比克隆卡更快,因为这涉及为新的 Card 实例分配内存(这很昂贵)并且该临时实例还必须由垃圾收集器释放(这也是贵)。

您在评论中提到您将卡片传递给较低级别​​的代码 - 如果您没有对数组(以及卡片位置)的反向引用,您将无法轻松交换cards - 在 AS3 中,所有输入参数都是副本(原始类型的值的副本或复杂对象的引用的副本 - 函数中输入参数的更改在外部不可见)。

编辑:将函数从 clone 重命名为 copyFrom,正如 aaron 所指出的。似乎克隆应该用作 objA = objB.clone()

此时,我在 Cards class 中添加了一个 copyFrom() 函数,这样

var temp:Cards = new Cards(...);
var a:Cards = new Cards(...);
...
temp.copyFrom(a);
...

temp 将从 a.

复制所有内容
public function swapCard(cardA:Cards, cardB:Cards) {
    var temp:Cards = new Cards();
    temp.copyFrom(cardA);
    cardA.copyFrom(cardB);
    cardB.copyFrom(temp);
}

我等一个星期左右看看有没有其他选择

这里存在很深的误解。问题是关于对象引用,但 PO 根本没有尝试交换任何对象引用。

问题出在PO不理解变量和对象的区别。他正在尝试交换 variable/object 引用,这当然是动态不可能的。他想用一个函数使变量持有对对象 A 的引用,将其对象引用与另一个变量交换。由于可以传递对象但不能传递变量(因为它们只是持有者(而不是指针)),所以如果不直接使用给定变量,则无法完成任务。

继续:

变量不是对象! 变量持有对对象的引用。 变量不能在函数中传递或在函数中引用,因为它们不是对象。

你已经有了一些很好的答案,但根据与我的来回评论,这是我的建议(我使用 "left" 和 "right" 命名,因为它有助于我形象化,但是没关系):

function swapCard(leftCards:Array, leftCard:Card, rightCards:Array, rightCard:Card):void {
    var leftIndex:int = leftCards.indexOf(leftCard);
    var rightIndex:int = rightCards.indexOf(rightCard);
    leftCards[leftIndex] = rightCard;
    rightCards[rightIndex] = leftCard;
}

现在您可以像这样交换您发布的两个示例中的卡片:

swapCard(player1.hand, player1.hand[s], player2.hand, player2.hand[t]);

swapCard(player1.hand, player1.hand[s], player1.deck, player1.deck[rand]);

但是请注意,虽然这会交换数组中的卡片,但不会交换对这些数组中卡片的直接引用。也就是说:

var a:Card = player1.hand[0];
var b:Card = player2.hand[0];
swapCard(player1.hand, a, player2.hand, b);
// does not change the references a and b, they still refer to the same card
a == player2.hand[0];
a != player1.hand[0];
b == player1.hand[0];
b != player2.hand[0];

通常,这类事情是通过调度 "changed" 事件来处理的,这样任何关心玩家手牌数组状态的代码都会知道重新评估手牌的状态。