使用 `eqv` 进行对象哈希查找
Object Hash Lookup with `eqv`
有没有一种方法可以在使用对象键时使用 eqv
查找哈希值而不循环遍历键值对?
通过在声明时指定键的类型,可以在散列中使用对象键:
class Foo { has $.bar };
my Foo $a .= new(:bar(1));
my %h{Foo} = $a => 'A', Foo.new(:bar(2)) => 'B';
但是,键查找使用身份运算符 ===
,只有当它是同一对象而不是等效对象时,它才会 return 值:
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)
查看 documentation for "===",最后一行表明该运算符基于 .WHICH 并且 "... 所有值类型必须覆盖方法 WHICH。" 这就是为什么如果您创建两个具有相同字符串值的单独项目,"===" returns 真.
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 的某些挂钩,不如复制 "value types" 的方式 - 即屠夫(某种程度上)的想法身份。上面显示的字符串的 .WHICH 方法只是 returns 类型名称和内容与 '|' 连接。为什么不做同样的事情;
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
当然,成本很小 - 这个 class 的实例的身份概念,好吧 - 可以说很有趣。有什么影响?唯一立即想到的是,如果您打算使用某种对象持久性框架,它会将 现在看起来相同 的不同实例压缩成一个(也许)。
具有相同属性数据的不同对象将无法区分 - 这就是为什么我在发布此答案之前犹豫不决的原因。 OTOH,它是你的 class,它是你的应用程序,因此,根据 size/importance 等,这可能是一个很好的方法。
如果您不喜欢内置后环固定,请提供您自己的。
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
有没有一种方法可以在使用对象键时使用 eqv
查找哈希值而不循环遍历键值对?
通过在声明时指定键的类型,可以在散列中使用对象键:
class Foo { has $.bar };
my Foo $a .= new(:bar(1));
my %h{Foo} = $a => 'A', Foo.new(:bar(2)) => 'B';
但是,键查找使用身份运算符 ===
,只有当它是同一对象而不是等效对象时,它才会 return 值:
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)
查看 documentation for "===",最后一行表明该运算符基于 .WHICH 并且 "... 所有值类型必须覆盖方法 WHICH。" 这就是为什么如果您创建两个具有相同字符串值的单独项目,"===" returns 真.
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 的某些挂钩,不如复制 "value types" 的方式 - 即屠夫(某种程度上)的想法身份。上面显示的字符串的 .WHICH 方法只是 returns 类型名称和内容与 '|' 连接。为什么不做同样的事情;
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
当然,成本很小 - 这个 class 的实例的身份概念,好吧 - 可以说很有趣。有什么影响?唯一立即想到的是,如果您打算使用某种对象持久性框架,它会将 现在看起来相同 的不同实例压缩成一个(也许)。
具有相同属性数据的不同对象将无法区分 - 这就是为什么我在发布此答案之前犹豫不决的原因。 OTOH,它是你的 class,它是你的应用程序,因此,根据 size/importance 等,这可能是一个很好的方法。
如果您不喜欢内置后环固定,请提供您自己的。
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