使用对象密钥时,有没有办法使用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 :(得分:2)
查看documentation for "===",最后一行显示运算符基于 .WHICH ,而“...所有值类型必须覆盖方法WHICH。”< / em>这就是为什么如果您使用相同的字符串值创建两个单独的项目,“===”会返回 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,它是你的班级,它的应用程序,所以,根据大小/重要性等,它可能是一个很好的方法。
答案 1 :(得分: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