31 Stimmen

Wie sollte ich Perl-Referenzen vergleichen?

Ich möchte prüfen, ob zwei Referenzen auf dasselbe Objekt verweisen. Es scheint, ich kann einfach verwenden

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

wie erwähnt in perlref aber ich erinnere mich vage daran, eine Funktion für den gleichen Zweck gesehen zu haben. Gibt es einen Grund, warum ich nicht den einfachen numerischen Gleichheitstest verwenden sollte?

Beachten Sie, dass ich nur wissen möchte, ob die Verweise auf genau dasselbe Objekt verweisen. Ich suche nicht nach einer Möglichkeit, den Inhalt des Objekts/der Objekte zu vergleichen.

27voto

rafl Punkte 11598

Verweise werden standardmäßig zu ihren Adressen nummeriert. Diese Referenzadressen sind für jede Referenz eindeutig, so dass sie oft bei Gleichheitsprüfungen verwendet werden können.

In dem von Ihnen gezeigten Ausschnitt müssen Sie jedoch zunächst sicherstellen, dass beide $ref1 y $ref2 sind eigentlich Referenzen. Andernfalls könnten Sie falsche Ergebnisse erhalten, da reguläre Skalare Referenzadressen enthalten.

Außerdem gibt es keine Garantie dafür, dass Verweise auf ihre Adresse nummeriert werden. Objekte können zum Beispiel durch Überladen den Wert beeinflussen, den sie in verschiedenen Kontexten zurückgeben.

Ein soliderer Weg, als Referenzen direkt auf numerische Gleichheit zu vergleichen, wäre die Verwendung der refaddr Funktion, wie sie von Scalar::Util nachdem Sie sich vergewissert haben, dass beide Seiten tatsächlich Referenzen sind.

2 Stimmen

Wenn Sie eine Klasse verwenden, deren Objekte eine Nummierung haben ( 0+ ) Überlast oder eine == Überlast (vielleicht über <=> ), dann ist es möglich, dass Sie tatsächlich wollen sein abgefangenes, übliches Gefühl der Gleichheit. Eine pauschale Aussage zu treffen, ohne diese Erwägungen zu erwähnen, scheint zu einfach zu sein. Abgesehen davon kann ich mir nicht viele Szenarien vorstellen, in denen der Codepfad, der von der Modulfunktion genommen wird, ein kritischer Pfad wäre, aus dem Sie versuchen, das letzte bisschen Leistung herauszuholen, das Sie können. Aber wenn es so wäre, würden Sie natürlich eine normale == .

0 Stimmen

Einverstanden. Deshalb hat Ihre Antwort von mir eine höhere Bewertung erhalten, weil Sie genau das erwähnt haben. Es gibt viele Fälle, in denen man Dinge auf ihre Gleichheit hin vergleichen möchte, und die Art der Gleichheit sollte für jeden Fall individuell betrachtet werden. Nichtsdestotrotz war die Frage ziemlich spezifisch und erhielt daher eine spezifische Antwort.

0 Stimmen

Sie hätte auch eine konkrete Antwort verdient. Deshalb hast du mein Upvote bekommen.

17voto

Ether Punkte 51044

Die Funktion, die Sie suchen, ist refaddr von Skalar::Util (nachdem sichergestellt wurde, dass es sich bei den zu vergleichenden Werten tatsächlich um Referenzen handelt):

use Scalar::Util 'refaddr';

if ($obj1 and ref($obj1) and $obj2 and ref($obj2) and
    refaddr($obj1) == refaddr($obj2))
{
    # objects are the same...
}

2 Stimmen

Die außerordentlichen Maßnahmen, die von cpan/List-Util/lib/Scalar/Util/PP.pm Funktion refaddr(), um die tatsächliche Adresse des Referenten zu ermitteln, werden nur von den Maßnahmen der Funktion blessed() übertroffen, um den Paketnamen zu finden.

4 Stimmen

Glücklicherweise sind die List-Util-Distribution und das darin enthaltene Scalar::Util-Modul Kernmodule, und der Kern wird mit einem C-Compiler erstellt, so dass so gut wie jeder den Luxus hat, die C-Version von Scalar::Util::refaddr zu verwenden, die so gut wie nur aus einem Flag-Check und einer Dereferenz besteht.

0 Stimmen

Es gibt tatsächlich einen Test im mktables-Code, um festzustellen, ob es sich um einen schnellen Scalar::Util handelt oder nicht. Ich hätte daran denken sollen, dass es einfach ein C-Aufruf sein könnte.

8voto

tchrist Punkte 76479

Ich muss davon ausgehen, dass Ihr #comment darüber, wie billig (=schnell) der Gleichheitstest ist, war nicht ohne Grund da. In Anbetracht dessen sollten Sie wahrscheinlich weiterhin den billigen Gleichheitstest verwenden. Er ist sehr schnell, viel schneller als eq geschweige denn als irgendeine Art von tiefem Vergleich.

Es ist möglich, dass ein Objekt mit einer direkt oder indirekt überladenen == Der Betreiber könnte den Test für seine eigenen Zwecke missbrauchen. Wenn er aber est Wenn Sie das tun, werden Sie vielleicht sogar seine vermittelte Antwort vorziehen.

Welchen Ansatz Sie wählen, kann davon abhängen, was Sie über die Klassen des Objekts wissen. Ansätze, die für allgemeine Fälle gelten, sind für spezielle Fälle nicht immer optimal. Je mehr Sie über etwas wissen, desto mehr können Sie es optimieren - und umgekehrt.

Wenn Sie also wissen dass Sie keine Klasse mit anwendbaren Überladungen verwenden, gibt es keinen Grund, eine nicht gebaute Bibliotheksfunktion einzuschleppen, und einen guten Grund, es nicht zu tun. Wenn Sie nicht über das Überladen wissen, oder Sie wissen über sie und wollen nicht, dass sie gelten, dann vielleicht nehmen Sie die langsame Ansatz.

Solange Sie verstehen. Es ist ein Fehler, den einen Ansatz für richtig und den anderen für falsch zu halten. Jede hat ihren Zweck. Wenn es immer falsch wäre, das zu tun, was Sie gerade tun, dann wäre dieser Vorgang entweder verboten oder es würde zumindest davor gewarnt.

Sie werden feststellen, dass es sich um no so gekennzeichnet.

2 Stimmen

Man sollte meinen, dass all die Ablehner den Mut hätten, genau zu sagen, was sie denken, dass ich falsch gesagt habe. Aber das tun sie nicht. Offensichtlich ziehen sie anonyme, versteckte Anschuldigungen einem vernünftigen Diskurs vor. Wenn Sie Ihre Stimme nicht rechtfertigen können, sollten Sie sie vielleicht nicht abgeben.

2 Stimmen

Ich habe kein Problem mit dem, was Sie gepostet haben (und habe es auch nicht heruntergestuft), aber ich finde es interessant, dass viele Poster Erklärungen für Herabstufungen verlangen, aber nicht für Hochstufungen. Ich verbringe keine Zeit damit, die rund 20 Upvotes zu rechtfertigen, die ich jeden Tag gebe.

5 Stimmen

@friedo: Wenn Sie glauben, dass ich Recht habe, genügt es zu wissen, dass Sie glauben, dass ich Recht habe. (Wenn es einen bestimmten Punkt gibt, der hervorgehoben werden sollte, sind "+1 für..."-Kommentare jedoch ziemlich üblich). Wenn Sie denken, ich liege falsch, möchte ich wissen warum Sie denken, dass ich falsch liege, damit ich entweder meine Aussage klarstellen, Ihre Einwände widerlegen oder vielleicht sogar (Schrecken des Schreckens) feststellen kann, dass Ihre Einwände zutreffend sind und ich etwas daraus lernen kann. Aus diesem Grund möchte ich zumindest Kommentare zu "Downvotes", während mir "Upvotes" egal sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X