Как я должен сравнивать ссылки Perl?

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

if ($ref1 == $ref2) { 
 # cheap numeric compare of references
 print "refs 1 and 2 refer to the same thing\n";
}

как упоминалось в perlref, но я смутно припоминаю, что видел использование какой-то функции для той же цели. Есть ли причина, по которой мне не следует использовать простой числовой тест на равенство?

Примечание. Я только хочу знать, указывают ли ссылки на один и тот же объект. Я не ищу способ сравнить содержимое объекта (ов).


person David B    schedule 31.10.2010    source источник


Ответы (3)


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

Однако в показанном фрагменте вам сначала нужно убедиться, что и $ref1, и $ref2 на самом деле являются ссылками. В противном случае вы можете получить неправильные результаты из-за обычных скаляров, содержащих ссылочные адреса.

Также ничто не гарантирует нумерацию ссылок по их адресу. Объекты, например, могут использовать перегрузку, чтобы влиять на значение, которое они возвращают в различных контекстах.

Более надежным способом, чем сравнение ссылок напрямую на числовое равенство, было бы использование функции refaddr, предоставляемой Scalar::Util. , убедившись, что обе стороны действительно являются ссылками.

person rafl    schedule 31.10.2010
comment
Если вы используете класс, объекты которого имеют перегрузку нумерации (0+) или перегрузку == (возможно, через <=>), то возможно, что вы на самом деле хотите его перехваченное, пользовательское чувство равенства. Делать общее заявление без упоминания этих соображений кажется слишком поверхностным. Тем не менее, я не могу придумать много сценариев, в которых путь кода, выбранный функцией модуля, был бы критическим путем, из которого вы пытаетесь выжать все возможное из производительности. Но если бы это было так, вы, конечно, хотели бы использовать обычный ==. - person tchrist; 31.10.2010
comment
Согласованный. Вот почему ваш ответ получил от меня одобрение за упоминание именно этого. Есть много случаев, когда может потребоваться сравнить вещи на равенство, и тип равенства, который следует использовать, следует рассматривать для каждого случая индивидуально. Тем не менее, вопрос был достаточно конкретным, поэтому и получил конкретный ответ. - person rafl; 31.10.2010
comment
Это тоже заслуживает конкретного ответа. Вот почему вы получили мой голос. ☺ - person tchrist; 01.11.2010

Функция, которую вы ищете, это refaddr из Scalar::Util (после проверки того, что сравниваемые значения действительно являются ссылками):

use Scalar::Util 'refaddr';

if ($obj1 and ref($obj1) and $obj2 and ref($obj2) and
    refaddr($obj1) == refaddr($obj2))
{
    # objects are the same...
}
person Ether    schedule 31.10.2010
comment
Экстраординарные меры, предпринятые функцией refaddr() из cpan/List-Util/lib/Scalar/Util/PP.pm для определения реального адреса референта, превосходят только меры функции благословения() по поиску имени пакета. - person tchrist; 31.10.2010
comment
К счастью, хотя дистрибутив List-Util и содержащийся в нем модуль Scalar::Util являются базовыми модулями, а ядро ​​построено с помощью компилятора C, практически каждый может позволить себе роскошь использования C-версии Scalar::Util. ::refaddr, который представляет собой всего лишь одну проверку флага и разыменование. - person rafl; 31.10.2010
comment
На самом деле в коде mktables есть проверка, является ли это быстрым Scalar::Util или нет. Я должен был помнить, что это может быть просто вызов C. - person tchrist; 01.11.2010
comment
+1 за единственный ответ с фрагментом кода. На самом деле вы можете сэкономить 2 проверки, потому что ref($obj) оценивается как false, даже если $obj равно undef. Так может быть, избавиться от условий $obj1 и $obj2? - person Daniel Böhmer; 21.01.2015

Я должен предположить, что ваше #commentо том, насколько дешевым (= быстрым) является тест на равенство, было не просто так. Учитывая это, вам, вероятно, следует продолжать использовать дешевый тест на равенство. Это очень быстро, намного быстрее, чем eq, не говоря уже о любом глубоком сравнении.

Возможно, что объект с прямо или косвенно перегруженным оператором == может узурпировать тест в своих целях. Но если он делает это, вы даже можете предпочесть его опосредованный ответ.

Какой подход вы выберете, может зависеть от того, что вы знаете о классах объекта. Подходы, применимые к общим случаям, не всегда оптимальны для конкретных. Чем больше вы о чем-то знаете, тем лучше вы можете это оптимизировать  — и наоборот.

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

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

Вы заметите, что он не так помечен.

person tchrist    schedule 31.10.2010
comment
Вы могли бы подумать, что у всех противников хватило бы смелости объяснить, что, по их мнению, я сказал неправильно. Но это не так. Таким образом, очевидно, они предпочитают анонимные скрытые выстрелы аргументированному дискурсу. Если вы не можете обосновать свой голос, возможно, вам не стоит его делать. - person tchrist; 31.10.2010
comment
У меня нет проблем с тем, что вы опубликовали (и не проголосовали против), но я действительно думаю, что интересно, что многие авторы требуют объяснений для отрицательных голосов, но не для положительных. Я не трачу время на оправдание 20 с лишним голосов, которые я даю каждый день. - person friedo; 31.10.2010
comment
@friedo: Если вы думаете, что я прав, достаточно знать, что вы думаете, что я прав. (Тем не менее, если есть какой-то конкретный момент, который стоит подчеркнуть, +1 за... комментарии довольно распространены.) Если вы думаете, что я ошибаюсь, я хочу знать, почему вы думаете, что я ошибаюсь. чтобы я мог либо уточнить свое утверждение, либо опровергнуть ваши возражения, а может быть даже (ужас ужасов) осознать, что ваши возражения точны и чему-то научиться из них. Вот почему я, по крайней мере, хочу комментировать отрицательные голоса, но в любом случае не забочусь о положительных. - person Dave Sherohman; 01.11.2010