Интересная хэш-ситуация AS3. Действительно ли используется строгое равенство, как говорится в документации? - PullRequest
3 голосов
/ 25 мая 2010

AS3 код:

import flash.utils.Dictionary;
var num1:Number = Number.NaN;
var num2:Number = Math.sqrt(-1);
var dic:Dictionary = new Dictionary( true );
trace(num1); //NaN
trace(num2); //NaN
dic[num1] = "A";
trace( num1 == num2 ); //false
trace( num1 === num2 ); //false
trace( dic[num1] ); //A
trace( dic[num2] ); //A

Относительно метода сравнения ключей ... "Класс Dictionary позволяет создавать динамическую коллекцию свойств, которая использует строгое равенство (===) для сравнения ключей. Когда объект используется в качестве ключа, идентификатор объекта используется для поиска объекта, и не значение, возвращаемое вызовом toString () для него. "

Если словарь использует строгое равенство, как говорится в документации, то как получается, что num1 === num2 является ложным, и все же dic [num1] разрешается в тот же слот хеша, что и dic [num2]?

Ответы [ 2 ]

2 голосов
/ 25 мая 2010

Описание, данное Adobe, не является ни точным, ни правильным, если честно, но оно проще и охватывает большинство случаев.

Вам следует попробовать следующее:

for (var key:* in dic) trace(getQualifiedClassName(key));//will give you 'String'

это поведение также верно для Array и Object.

Как правило: int остается int, а любой другой ключ преобразуется в его строковое представление (включая логические значения и значения с плавающей запятой, а также null и undefined).

Класс Dictionary отличается тем, что он не преобразует непримитивные объекты в String, а непосредственно использует их в качестве ключа. Их способ обработки всех других значений «унаследован» Object, если хотите.

Как правило, Object состоит из 2 хешей, один для строки и один для целочисленных ключей. И Dictionary добавляет еще один хэш, возможно, просто используя адрес памяти объектов в качестве целочисленного ключа.

edit: Не совсем ответ на конкретный вопрос, но момент, который я хочу подробно объяснить в ответ на комментарий Трийнко:

Hacky? Вы имеете в виду, заставить его работать в Кстати, он не предназначен для работы? Что ж... так как он не предназначен для обработки 64-разрядные целые числа, конечно, это хак. Но 64-битные это 64-битные, будь то они интерпретируются как целое число или с плавающей точкой.

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

Но тогда использование их строкового представления в качестве ключа (что недопустимо, если вы используете float в качестве ключа) является простым самоубийством:

var f1:Number = 1000000000000003000000000.0;
var f2:Number = 1000000000000002000000000.0;
trace(f1 == f2);//false
trace(String(f1) == String(f2));//true ... kabooooom

Вам будет сложно определить, когда столкнутся 2 64-битные целые, поскольку обязательным условием является то, что строковое представление их значений, интерпретируемых как числа с плавающей запятой, должно быть одинаковым. Кроме того, разные версии проигрывателей могут иметь различное преобразование строк с плавающей запятой, как и альтернативные среды выполнения, такие как LightSpark . Я действительно не хотел бы полагаться на это. Это приводит к появлению ошибок, которые появляются из ниоткуда, когда данных достаточно, чтобы вызвать коллизию. И вам не понравится выслеживать их.

Кроме того, плавающие ключи работают хуже, так как они должны быть преобразованы в строки перед использованием для поиска хеша. Если вас действительно беспокоит размер, вам придется передавать данные как 64-битные целочисленные значения и преобразовывать их в шестнадцатеричную строку только на стороне флэш-памяти.
Тем не менее, я хотел бы отметить, что многие люди чрезвычайно довольны использованием XML или JSON, что приводит к гораздо худшим накладным расходам.

Пропускная способность и любые другие аппаратные ресурсы дешевы. Разработка дорогая. Вы должны писать свои приложения так, чтобы они были удобными в обслуживании и надежными, иначе в долгосрочной перспективе они будут стоить вам дороже.

Greetz
back2dos

0 голосов
/ 26 мая 2010

Боюсь, вы споткнулись о что-то довольно хитрое. Dictionary работает так, как объявлено в том смысле, что использует идентификаторы объектов для ключей, и не проверяет объекты по значению. И в большинстве случаев это работает так же, как использование строгого равенства, потому что в большинстве случаев две ссылки на один и тот же объект строго равны друг другу.

Проблема заключается в том, что спецификация AS3 имеет особый случай: все сравнения с NaN по определению считаются ложными - даже сравнения между NaN и самим собой (что и делает ваш пример кода). Существует даже предупреждение во время компиляции об этом эффекте, если NaN явно появляется в сравнении. Кроме того, существуют другие особые случаи для некоторых других примитивов, таких как 'true' и 'undefined'.

Должно быть легко увидеть, что происходит, если вы попробуете другое значение теста:

import flash.utils.Dictionary;
var num1:Number = Number.POSITIVE_INFINITY;
var num2:Number = 1 / 0;
var dic:Dictionary = new Dictionary( true );
trace(num1); // Infinity
trace(num2); // Infinity
dic[num1] = "A";
trace( num1 == num2 ); // true!!
trace( num1 === num2 ); // true!!
trace( dic[num1] ); //A
trace( dic[num2] ); //A

Это может показаться странным в зависимости от того, к каким языкам вы привыкли, но все это означает, что когда вы создаете две разные ссылки на бесконечность, AS3 не дает вам два разных объекта, значение которых равно бесконечности, он дает вам два ссылки на тот же объект бесконечности. Следовательно, ссылки строго совпадают и имеют одинаковое значение. И использование NaN вместо Infinity работает одинаково во всех отношениях, за исключением части, в которой вы сравниваете значение с самим собой - когда оно возвращает false, поскольку NaN является особым случаем.

...