#apache-flex #arraycollection
#apache-flex #arraycollection
Вопрос:
Я хочу установить 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;
}
Комментарии:
1. 1 За правильное использование терминов, случайно или нет. Смотрите Стратегию оценки . Хотя «передавать по значению [ссылки на объект]» лучше называть «передавать по объекту» или «передавать с помощью совместного использования объектов», чтобы избежать этой путаницы. Я просто знаю, что кто-то собирается сказать «Но они передаются по ссылке!» (и это, возможно, даже привело к текущей путанице, если термин был неправильно использован в какой-то документации или руководстве 😉
Ответ №1:
Пожалуйста, ознакомьтесь со стратегией оценки.
AS использует «передачу по объекту» / «передачу при совместном использовании объектов». То есть передается «объект» (не копия, клон или дубликат), и любые модификации объекта являются общими.
Однако присвоение _ac2 = _ac1
изменяет только значение переменной параметра [функции local] и не повлияет ни на какие переменные во время вызова функции. Единственное, что передается, — это значения («объекты»), которые являются результатом вычисления переменных (или любого произвольного выражения), используемых при вызове функции.
Это потому, что, как указано выше, используемая стратегия — «передавать по объекту», а не (как указано в документации «передавать по ссылке», что на самом деле означает «передавать по значению [ссылки]» или просто … «передача по объекту»). То есть, термин «передача по ссылке» фактически используется неправильно и, следовательно, сбивает с толку. (Это неправильно используется в ряде языков и документации. Это тяжелая битва, пытающаяся прийти к общему значению.)
Если бы это было действительно «передачей по ссылке», то присвоение нового значения _ac2
распространилось бы. (Прежде чем создавать комментарий, в котором говорится, что такое «передавать по ссылке», пожалуйста, посмотрите ссылку вверху и учтите, что «передавать по ссылке» относится к C # out/ref
, VB ByRef
, TSQL output
и C (ссылка) amp;
— этих понятий нет в AS, Javascript или Java). Однако, как правильно отмечено в исходном сообщении (и дополнительном автоответчике), это не так — заключение: AS не поддерживает «передачу по ссылке»; более того, в документации (сбивающе с толку) используется термин «передача по ссылке» для обозначения «передача по объекту» / «передача при совместном использовании объектов».
Существует несколько способов распространения изменения, упорядоченных по порядку (моего) предпочтения:
-
Верните новое применимое значение:
AC2 = doSomeTransformation(AC1)
. Это, как правило, самый чистый. Избегайте побочных эффектов и неожиданного кода. Несколько значений могут быть возвращены, если они соответствующим образом обернуты в объект (или массив). -
Используйте замыкание:
doSomeTranformation(AC1, function (newValue) { AC2 = newValue })
где doSomeTransformation может выглядеть следующим образом:function doSomeTransformation(_ac1, finished) { ...; finished(_ac1) }
. Обычно я использую это только тогда, когда обратный вызов «выполняется в контексте» самой функции или при написании кода в стиле CPS. -
Изменяет объект (в конце концов, это «передача по объекту»). Это очень неприятно, но это сработает.
var blah = {AC2: null}; doSomeTransformation(ac1, blah); ...; laterOn(blah.AC2)
где doSomeTransformation может выглядеть следующим образомfunction doSomeTransformation(_ac1, b) { ...; b.AC2 = _ac1; }
. В целом не рекомендуется.
Удачного кодирования.
Применимые выдержки из стратегии оценки:
«вызов по ссылке»: (мой главный аргумент в пользу того, что «вызов по ссылке» используется неправильно, заключается в том, что у него уже есть четко определенное значение; перегруженный термин, принятый некоторыми языками, такими как AS и Python, просто добавляет путаницы)
При вычислении вызова по ссылке (также называемом передачей по ссылке) функция получает неявную ссылку на переменную, используемую в качестве аргумента, а не копию ее значения. Обычно это означает, что функция может изменять переменную, используемую в качестве аргумента — что-то, что будет видно ее вызывающей стороне.
«вызов по объекту» / «вызов с использованием общего доступа к объекту»: (но обратите внимание на то, где он признает несоответствие / локализацию этих терминов; термин «вызов по ссылке» часто используется неправильно, чтобы подразумевать эту семантику, и «вызов по значению [ссылки]» используется в некоторых контекстах для обозначения того же самого)
Семантика совместного использования вызовов отличается от вызова по ссылке тем, что присваивания аргументам функции внутри функции не видны вызывающей стороне (в отличие от семантики по ссылке), поэтому, например, если была передана переменная, невозможно имитировать присвоение этой переменной в области видимости вызывающей стороны. Однако, поскольку функция имеет доступ к тому же объекту, что и вызывающий (копия не создается), изменения в этих объектах, если объекты изменяемы, внутри функции видны вызывающему, что может показаться отличным от семантики вызова по значению.
Ответ №2:
Аргументы функции в ActionScript передаются по значению, а не по ссылке. Это абсолютно то же самое, что и в Java. Подробнее вы можете прочитать здесь.
Комментарии:
1. но это, похоже, указывает на то, что оно должно передаваться по ссылке: livedocs.adobe.com/flex/3/html /…
2. Хорошо, чтобы быть точным, перейдите по моей ссылке, и вы найдете описание, которое также полностью относится к ActionScript: «Java передает ссылки по значению точно так же, как и любой другой параметр. Это означает, что ссылки, передаваемые методу, фактически являются копиями исходных ссылок.»
3. 1 Это пока единственный правильный ответ. В документации неправильно используется «передача по ссылке» для обозначения «передачи путем совместного использования объектов» (или «передача по значению [ссылки]» для людей, которые любят ссылаться в указателях). Пожалуйста, ознакомьтесь со стратегией оценки . «Проблема» в том, что poster ожидает реальной «передачи по ссылке», которая не поддерживается в Javascript или Actionscript.
4. (Мой термин «неправильно» немного резковат, однако я придерживаюсь утверждения, что использование перегруженного термина только добавляет путаницы. Плакат несколько раз дает понять, что он ожидал реальной (или другой , если вы предпочитаете) семантики «передачи по ссылке».)
Ответ №3:
Проблема, которую я вижу, заключается в
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.
Комментарии:
1. Это совершенно неправильно.
addItemToArrayCollection( AC1 );
не имеет ничего общего со ссылками. Используя ваш код, AC1 имеет SomeObject, в то время как AC2 пуст, такой же, как код автора темы.
Ответ №4:
Я считаю, что @Constantiner на правильном пути, но я думаю, что в его объяснении не хватает деталей; поэтому я попытаюсь объяснить немного глубже; насколько я понимаю. Вы можете поправить меня, если я ошибаюсь.
Как указано в документах:
В ActionScript 3.0 все аргументы передаются по ссылке, потому что все значения хранятся как объекты. Однако объекты, принадлежащие к примитивным типам данных, которые включают Boolean, Number, 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. Документация неверна — она неправильно использует «передавать по ссылке» (как и документация Python) для обозначения «передавать путем совместного использования объектов», и в этом заключается суть всей этой «дилеммы». Итак, хотя в этом сообщении объясняется «передача путем совместного использования объектов», в нем не рассматривается вопрос posters 🙂 Плакат ожидал «передать по ссылке» (с правильным значением), чтобы разрешить модификацию переданной переменной в соответствии с C #,
out/ref
или VBByRef
, или C (ссылка)amp;
.2.
this
Трюк несколько интересен, но следует отметить, что он будет работать только в том случае, если метод if вызывается для глобального объекта (или явно для объекта, для которогоAC2
является членом — я думаю,this.AC2 = _ac1
это показывает больше намерения; желание состоит в том, чтобы изменитьAC2
(хотя и через локальный параметр_ac2
))3. @pst На основе исходного кода poster; У меня нет оснований полагать, что метод ac2 и переменная ac2 не являются частью одного и того же класса; но да, чтобы ссылка ‘this’ работала, оба метода должны находиться в классе, который содержит переменную ac2.
4. @pst Я признаю, что это первый раз, когда я услышал термин «передача путем совместного использования объектов». Как указано в статье Wikipeida: «термин «вызов путем совместного использования» не является общепринятым; терминология несовместима в разных источниках». У вас есть ссылка на утверждения о том, что документация неверна?
5. «Неправильно» звучит немного грубо и было использовано здесь как гипербола; мой ответ содержит больше деталей. Я нахожусь в поиске, чтобы искоренить это использование «передачи по ссылке», поскольку с его использованием нет способа описать реальную «передачу по ссылке». Кроме того, я нахожу, что «передавать по ссылке» (в данном контексте) и «передавать по значению [ссылки]» являются низкоуровневыми терминами (почему я должен заботиться о реализации?) когда точная семантика соответствует более подходящему термину. Вы абсолютно правы в том, что терминология непоследовательна, но я думаю, что использование увеличивается — я пытаюсь, черт возьми 😉