ActionScript 3 - Ссылка против ценности - PullRequest
4 голосов
/ 17 февраля 2010

Я думал, что у меня есть ссылки в AS3, но меня озадачивает следующее поведение:

// declarations for named individual reference later on
var myAmbientSound:Sound;
var myAmbientSoundLocation:String = "http://ambient_sound_location";

var myPeriodicSound:Sound;
var myPeriodicSoundLocation:String = "http://periodic_sound_location";

var myOccasionalSound:Sound;
var myOccasionalSoundLocation:String = "http://occasional_sound_location";

// for iterating through initialization routines
var mySoundArray:Array = [myAmbientSound, myPeriodicSound, myOccasionalSound];
var mySoundLocation:Array = [myAmbientSoundLocation, myPeriodicSoundLocation, myOccasionalSoundLocation];

// iterate through the array and initialize
for(var i:int = 0; i < mySoundArray.length; i++) {
    mySoundArray[i] = new Sound();
    mySoundArray[i].load(new URLRequest(mySoundLocation[i]));
}

На данный момент, я думаю, что mySoundArray[0] будет ссылаться на тот же объект, что и myAmbientSound; однако при доступе к myAmbientSound возникает исключение нулевого указателя, тогда как mySoundArray[0] работает как положено и ссылается на объект Sound. Что я тут недопонимаю?

Ответы [ 4 ]

7 голосов
/ 17 февраля 2010

Это больше похоже на ссылочные переменные Java, чем на указатели C.

var myAmbientSound:Sound;
var myPeriodicSound:Sound;
var myOccasionalSound:Sound;
//these variables are not initialized and hence contain null values

Теперь вы создаете массив, содержащий текущие значения (нулевые) этих переменных

var mySoundArray:Array = [myAmbientSound, myPeriodicSound, myOccasionalSound];

Массив теперь содержит три нуля [null, null, null], а не три указателя на Sound объектов, как вы ожидаете.

Теперь, когда вы вызываете mySoundArray[0] = new Sound();, создается новый объект Sound, и его адрес назначается первому месту массива - он не изменяет переменную myAmbientSound.

3 голосов
/ 17 февраля 2010

Поскольку другие нашли время, чтобы найти очень хорошие объяснения, я вместо этого попытаюсь ответить на вопросы, которые вы задаете неявно:

На данный момент, я думаю, что mySoundArray[0] будет ссылаться на тот же объект, что и myAmbientSound

Но myAmbiendSound ни на что не ссылается. Из вашего кода:

var myAmbientSound:Sound;

Выше просто создает локальную переменную типа Sound, потенциальную ссылку. «Палец», который может указывать на что-то, с точки зрения неспециалистов. Все локальные переменные являются ссылками. И, кстати, не все ссылки являются локальными переменными, свойства объектов также являются ссылками, как и элементы Array и Vector. В любом случае, приведенное выше выражение не создает объект класса Sound. Он просто объявляет локальную переменную, которая может ссылаться на объект класса Sound. При объявлении он имеет специальное значение undefined.

Существует разница между объявлением переменной, как указано выше, и присвоением ей значения. Оператор new создает объект и возвращает ссылку на него. Оператор присваивания, =, приводит к тому, что все, что находится на левой стороне, независимо от того, что находится на правой стороне, грубо говоря.

Один из способов получить указанную выше локальную переменную для объекта:

myAmbientSound = new Sound();

Однако в вашем случае, как я уже сказал, переменная myAmbientSound имеет специальное значение undefined, поскольку вы просто объявили его, и ему еще не было присвоено значение. Кроме того, как видно из кода, он не ссылается ни на что в течение всего времени выполнения вашего фрагмента кода.

Теперь, прежде чем я объясню, что вы в итоге добавляете в свой массив с помощью строки:

 var mySoundArray:Array = [ myAmbientSound, ...

, вы должны помнить, что элементы массива, так же как и свойства объекта, тоже являются ссылками - например, mySoundArray[0] может ссылаться на объект, как mySoundArray[1] и т. Д.

Строка кода выше объявляет новую локальную переменную , а делает ее ссылкой на новый объект массива. Декларация и определение в одном заявлении.

Теперь, поскольку мы установили, что ваша локальная переменная myAmbiendSound содержит специальное значение undefined, ваш первый элемент массива в итоге ссылается на это же значение - undefined, , первоначально . Позже в цикле у вас будет первый элемент (или, если мы хотим быть хитрым, элемент с номером, на который ссылается переменная i), ссылающийся на новый объект Sound. В этот момент (и для всей области действия вашего фрагмента, как мы наблюдали), поскольку myAmbiendSound равно undefined, сравнение двух по равенству не удастся - они не ссылаются ни на тот же объект, ни на считаются ли объекты, на которые они ссылаются, «равными» (как работает = в AS3 - другая тема) - первая - undefined, а вторая указывает на Sound объект.

Также незначительное исправление: «доступ» к объекту не приводит к исключению во время выполнения. Попытка получить доступ к свойству (используя синтаксис с точечной нотацией) ссылки, которая не указывает на объект - приводит к исключению во время выполнения. Это как если бы вы написали trace(null.foo) - null не является объектом и, конечно, не имеет свойства с именем foo. То же самое касается undefined.

Кстати, null == undefined - это true, но null === undefined - это false. Просто говорю. В редких случаях (в зависимости, конечно), вам придется соблюдать эту деталь.

Надеюсь, это прояснит ситуацию. Я считаю это дополнением ко всему сказанному ранее здесь.

2 голосов
/ 17 февраля 2010

Как правило, ссылки в ActionScript, Java и других языках не рассматриваются как ссылки в C / C ++. Если бы ссылки работали как в C / C ++, написанный вами код был бы верным и работал бы так, как вы ожидали. В общем, вы должны пытаться думать о ссылках как о автореференсированных указателях. Ваш код является отличным примером различия между ссылками на C / C ++ и современными ссылками.

Вот пример последствий этого поведения применительно к сборщику мусора:

var someRef:Sound = new Sound();
someRef = null;

Тогда объект Sound, который я создал в первой строке, все еще существует и может продолжать существовать. Это важно помнить, поскольку, регистрируя прослушиватели событий в AS3, вы создаете дополнительную ссылку на них, предотвращая их уничтожение GC. Вот почему вы почти всегда должны использовать полный вызов AddEventListener, заставляя его использовать слабые ссылки (которые не учитываются для GC).

Кроме того, имейте в виду, что все вызовы функций являются ByVal в AS3. Так что этот код не будет работать:

function initSound(a:Sound, b:String):void {
    a = new Sound();
    a.load(new URLRequest(b);
}

var myAmbientSound:Sound;
var myAmbientSoundLocation:String = "http://ambient_sound_location";
initSound(myAmbientSound, myAmbientSoundLocation);

Хорошей новостью является то, что большинство языков со встроенной сборкой мусора имеют одинаковое поведение для ссылок, поэтому, как только вы освоите их, вы сможете выбрать эти языки еще быстрее.

1 голос
/ 17 февраля 2010

Определение переменной не создает указатель.

// This line is only creating a QName, but no pointer.
// Value of "myAmbientSound" is "null".
var myAmbientSound : Sound;

// Here, you put the reference pointed by myAmbientSound into the array.
// It is null, so mySoundArray[0] will also be null.
var mySoundArray : Array = [myAmbientSound];

// Here, you assign a new pointer to the index 0 of mySoundArray.
// It is simply overwriting the "null" value, but there is no
// connection to myAmbientSound.
mySoundArray[0] = new Sound();

// myAmbientSound is still null, as it is still pointing to nothing.
trace(myAmbientSound);  // null
// But index 0 of mySoundArray holds a pointer to the sound you instanciated.
trace(mySoundArray[0]); // [Object Sound]

Чтобы достичь того, что вы ищете, вы должны сделать что-то вроде этого:

// Creating the variable and pointing it to an object instance.
var myAmbientSound : Sound = new Sound();

// Here, the pointer isn't null, so the reference can be added to the array.
var mySoundArray : Array = [myAmbientSound];

// And now, both accessors points to the same object instance.
trace(myAmbientSound);  // [Object Sound]
trace(mySoundArray[0]); // [Object Sound]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...