2016-03-03 42 views
3

有沒有一種方法可以使用eqv來查找散列值,而不必在使用對象鍵時循環鍵值對?使用`eqv`對象哈希查找

有可能通過在聲明中指定鍵的類型使用對象鍵在哈希:

class Foo { has $.bar }; 
my Foo $a .= new(:bar(1)); 
my %h{Foo} = $a => 'A', Foo.new(:bar(2)) => 'B'; 

然而,鍵查找使用的身份運營商===將返回只有當它是同一個對象的值而不是一個等同一個:

my Foo $a-prime .= new(:bar(1)); 
say $a eqv $a-prime; # True 
say $a === $a-prime; # False 
say %h{$a};   # A 
say %h{$a-prime};  # (Any) 
+0

如何嚴重的是你的應用程序?我有一個答案,在任何生產環境中都是不可接受的,但是如果你只是探索什麼可能是爲了好玩,它可能是有趣的。 – Marty

回答

2

望着documentation for "===",最後一行顯示,運營商基於。其中「...所有值類型都必須覆蓋方法WHICH。」這就是爲什麼如果您創建兩個具有相同字符串值的單獨項目,「===」返回True

my $a = "Hello World"; 
my $b = join " ", "Hello", "World"; 

say $a === $b;  # True even though different items - because same value 
say $a.WHICH ;  # "Str|Hello World" 
say $b.WHICH ;  # (same as above) which is why "===" returns True 

因此,而不是創建自己的容器類型或使用一些鉤子的subscripts,你可以直接複製的方式「值類型」做到這一點 - 即屠夫(有些什麼)身份的想法。上面顯示的用於字符串的.WHICH方法只是返回類型名稱和內容,用'|'。爲什麼不做同樣的事情;

class Foo { 
    has $.bar; 
    multi method WHICH(Foo:D:) { "Foo|" ~ $!bar.Str } 
} 

my Foo $a .= new(:bar(1)); 
my %h{Foo} = $a => 'A', Foo.new(:bar(2)) => 'B'; 

my Foo $a-prime .= new(:bar(1)); 
say $a eqv $a-prime; # True 
say $a === $a-prime; # True 
say %h{$a};   # A 
say %h{$a-prime};  # A 

有一個小的費用,當然 - 身份的這一類的實例的概念,很好 - 讓我們說有趣。什麼是影響?唯一要緊記的是,如果你打算使用某種對象持久化框架,它將把現在看起來相同的變成一個(可能)的不同實例。

具有相同屬性數據的不同對象將無法區分 - 這就是爲什麼我發佈此答案之前猶豫了。 OTOH,它的課程,它的應用程序,這取決於大小/重要性等,這可能是一個很好的方法來做到這一點。

+0

我希望可以用於定義的特徵。不幸的是,對我來說,src/core/Hash.pm主要是npq。 src確實給出了一個如何用TypeHash角色完成這個例子的例子。也許可以使用duck類型來實現HASH-CODE方法的對象,而不是WHICH。 –

+0

我相信本地對象是在nqp中完成的,因爲perl6在那時不存在(如果你知道我的意思)。作爲perl6用戶,我們可以在perl6中建立元對象(即如果你想忘記nqp)。但是,儘管如此,您將要將不同的對象($ a vs $ a-prime)映射到同一個關鍵字,以便明確地擺弄身份以清楚說明可能是一個好主意。也許實現「keyWHICH」或「myVALUE」或某些類似的東西,並使自定義哈希使用它來進行關鍵區分。不過,我建議的技術對於一條額外的線路來說並不壞(如果我自己說的話):-) – Marty

2

如果您不喜歡buildin postcircumfix,請提供您自己的。

class Foo { has $.bar }; 
my Foo $a .= new(:bar(1)); 
my %h{Foo} = $a => 'A', Foo.new(:bar(2)) => 'B'; 


multi sub postcircumfix:<{ }>(\SELF, WhateverCode $c) is raw { 
    gather for SELF.keys -> $k { 
     take $k if $c($k) 
    } 
} 

dd %h; 
dd %h{* eqv $a}; 

輸出

Hash[Any,Foo] %h = (my Any %{Foo} = (Foo.new(bar => 1)) => "A", (Foo.new(bar => 2)) => "B") 
(Foo.new(bar => 1),).Seq