Arraycollection передается в функцию по значению, а не по ссылке в flex 3 - PullRequest
10 голосов
/ 07 мая 2011

Я хочу установить arrayCollection # 2 = для arrayCollection # 1 через функцию в flex 3. Я передаю обе коллекции массивов в функцию и устанавливаю arrayCollection # 2 = arrayCollection # 1. Однако, похоже, что не передается arrayCollection # 2 по ссылке, потому что после вызова функции arrayCollection # 2 не изменилась. Насколько я понимаю, это должно быть передано по ссылке и работе, я делаю что-то не так? Ниже приведен код:

var AC1:ArrayCollection = new ArrayCollection;
var AC1.addItem(someObject);

var AC2:ArrayCollection = new ArrayCollection;

setAC2(AC1,AC2);
// AC2 is not set to AC1 after the function


private function setAC2(_ac1:ArrayCollection, _ac2:ArrayCollection):void
{
    _ac2 = _ac1;
}

Ответы [ 4 ]

6 голосов
/ 07 мая 2011

См. Оценочная стратегия .

AS использует «передача объектом» / «передача объектом совместного использования» . То есть передается «объект» (не копия, клон или дубликат), и любые модификации объекта передаются .

Однако, присваивание _ac2 = _ac1 только изменяет значение переменной параметра [local's function] и не будет влиять на какие-либо переменные во время вызова функции. Единственное, что передается, это значения («объекты»), которые являются результатом оценки переменных (или любого произвольного выражения), используемых при вызове функции.

Это связано с тем, что, как указано выше, используется стратегия «передача по объекту» , а не (как указано в документации «передача по ссылке», что на самом деле означает «передача по значению [ ссылка] "или просто ..." мимо объекта "). То есть термин «передача по ссылке» фактически используется неправильно и, следовательно, вводит в заблуждение . (Это неправильно используется в ряде языков и документации. Это тяжелая битва, пытаясь найти общий смысл.)

Если бы это было действительно"передачей по ссылке", тогда присвоение нового значения _ac2 распространялось бы. (Прежде чем написать комментарий о том, как AS «передается по ссылке», просмотрите ссылку вверху и учтите, что «передача по ссылке» охватывает случай C # out/ref, VB ByRef, TSQL output и C ++ ( ссылка) & - эти понятия не относятся к AS, Javascript или Java). Однако, как правильно отмечено в исходном сообщении (и дополнительном самоответе), дело обстоит не так - заключение: AS не поддерживает «передачу по ссылке»; , кроме того, документация ( сбивает с толку) использует термин «передача по ссылке» для обозначения «передача по объекту» / «передача по объекту совместного использования».

Существует несколько способов распространения изменения в порядке (моего) предпочтения:

  1. Возвращает новое применимое значение: AC2 = doSomeTransformation(AC1). Это вообще самое чистое. Избегайте побочных эффектов и удивительного кода. Несколько значений могут быть возвращены, если они обернуты в объект (или массив) в зависимости от ситуации.

  2. Используйте замыкание: doSomeTranformation(AC1, function (newValue) { AC2 = newValue }), где doSomeTransformation может выглядеть так: function doSomeTransformation(_ac1, finished) { ...; finished(_ac1) }. Я обычно использую это только тогда, когда обратный вызов «выполняется в контексте» самой функции или при написании кода в стиле CPS.

  3. Мутировать объект (в конце концов, AS - это «передача объектом»). Это очень неприятно, но это сработает. var blah = {AC2: null}; doSomeTransformation(ac1, blah); ...; laterOn(blah.AC2) где doSomeTransformation может выглядеть как function doSomeTransformation(_ac1, b) { ...; b.AC2 = _ac1; }. Вообще не рекомендуется.

Счастливого кодирования.


Применимые выдержки из Оценочная стратегия :

"вызов по ссылке": (мой основной аргумент для "вызова по ссылке", который используется неправильно , заключается в том, что он уже имеет четко определенное значение; перегруженный термин принят некоторые языки, такие как AS и Python, добавляют путаницу)

При оценке по ссылке (также называемой передачей по ссылке) функция получает неявную ссылку на переменную, используемую в качестве аргумента, а не копию ее значения. Как правило, это означает, что функция может изменить переменную, используемую в качестве аргумента, что будет видно ее вызывающей стороне .

«вызов по объекту» / «вызов по совместному использованию объекта»: (но обратите внимание на то, где он признает несоответствие / локализацию этих терминов; термин «вызов по ссылке» часто неправильно используют для подразумевают, что эта семантика и «вызов по значению [ссылки]» используется в некоторых контекстах, чтобы также означать то же самое)

Семантика call-by-share отличается от call-by-reference тем, что присваивания аргументам функции внутри функции не видны вызывающей стороне (в отличие от семантики by-reference), например, если передана переменная, , невозможно смоделировать присваивание этой переменной в области действия вызывающего . Однако, поскольку функция имеет доступ к тому же объекту, что и вызывающий объект (копия не создается), мутации этих объектов, если объекты являются изменяемыми, внутри функции видны вызывающему объекту, что может отличаться от вызова семантика значения.

3 голосов
/ 07 мая 2011

Аргументы функции в ActionScript передаются по значению, а не по ссылке.Это абсолютно так же, как в Java.Подробнее можно прочитать здесь .

1 голос
/ 07 мая 2011

Я считаю, что @Constantiner находится на правильном пути, но я думаю, что в его объяснении отсутствуют детали; поэтому я попытаюсь объяснить немного глубже; как я понимаю. Я могу исправить меня, если я ошибаюсь.

Как указано в документах :

В ActionScript 3.0 все аргументы передается по ссылке, потому что все значения хранятся в виде объектов. Тем не мение, объекты, которые принадлежат к примитиву типы данных, в том числе логические, Число, int, uint и String имеют специальные операторы, которые делают их вести себя так, как будто они прошли мимо значение.

Итак, ArrayCollection определенно является объектом, а не примитивным типом, поэтому его следует передавать по ссылке и действовать так, как если бы он передавался по ссылке. Но какова ваша ссылочная переменная для ArrayCollection. Концептуально это просто указатель на некоторое пространство памяти, которое содержит фактические данные коллекции. Вот моя попытка в некотором искусстве ASCII:

                  |---|
 ac1(variable)--> |   | (ActualArrayCollection1)
                  |---|

                  |---|
 ac2(variable)--> |   | (ActualArrayCollection2)
                  |---|

повторюсь, переменная ac1variable является указателем на некоторое пространство памяти. переменная ac2variable является указателем на другое пространство памяти. Когда вы передаете один из них в метод в качестве аргумента, он передается по ссылке. Итак, внутри метода у вас есть что-то вроде этого:

 ac1(variable)--> |---|
 ac1(argument)--> |   | (ActualArrayCollection1)
                  |---|

 ac2(variable)--> |---|
 ac2(argument)--> |   | (ActualArrayCollection2)
                  |---|

Таким образом, переменная ac1variable и ac1argument указывают на одно и то же пространство памяти; потому что каждый из них содержит одно и то же значение указателя. Тем не менее, ac1variable и ac1argument фактически содержат разные области памяти. Они не то же самое.

Когда метод запускает эту строку:

_ac2 = _ac1;

Вы получите что-то вроде этого:

 ac1(variable)--> |---|
 ac1(argument)--> |   | (ActualArrayCollection1)
 ac2(argument)--> |---|

 ac2(variable)--> |---|
                  |   | (ActualArrayCollection2)
                  |---|

Когда выполнение метода заканчивается, два аргумента исчезают, а исходные переменные-указатели остаются неизменными. Если вы хотите сделать прямое присвоение, подобное этому, внутри метода, вы можете получить доступ к глобальной переменной, используя ключевое слово this. Это должно сделать это:

   this._ac2 = _ac1;

Конечно, это может нанести ущерб цели инкапсуляции внутри метода, если вы обращаетесь к переменным уровня класса.

Я уверен, что эксперт по проектированию компиляторов и тому подобное съест это на завтрак и выплюнет. Я надеюсь, что мой ASCII-арт одинаков для разных браузеров / машин / ОС / и т. Д.

1 голос
/ 07 мая 2011

Проблема, с которой я сталкиваюсь:

var AC1.addItem(someObject);

Попробуйте добавить элемент в функцию.

var AC1:ArrayCollection = new ArrayCollection;
var AC2:ArrayCollection = new ArrayCollection;

addItemToArrayCollection( AC1 );
setAC2(AC1,AC2);
// AC2 should be pointing to the ArrayCollection that AC1 is pointing to.

private function setAC2(_ac1:ArrayCollection, _ac2:ArrayCollection):void
{
   _ac2 = _ac1;
}

private function addItemToArrayCollection( arrayCollection:ArrayCollection ):void
{
  arrayCollection.addItem( someObject );
}

Вы можете добавить точку останова после назначения и увидеть, что AC2 долженимеют тот же объект, что и AC1.

...