我可以编写一个行为类似于散列的对象吗?
Can I write an object that behaves like a hash?
在 Perl 中有 tie
。 Python 支持各种 协议 以便对象可以像字典一样运行。 Raku 有类似的东西吗?
IE。我可以定义一个行为类似于 Hash
的对象吗?那就是:我可以写 $myobject<key>
以结束我自己指定的例程吗?
在 raku
中,语法 <>
似乎是一个后环路运算符,可以通过 AT-KEY
和 EXISTS-KEY
中描述的多方法重载 https://docs.raku.org/language/subscripts#Methods_to_implement_for_associative_subscripting
Perl 在语言中内置了哈希功能。
因此,要扩展它以使对象的行为类似于哈希,您需要告诉运行时做一些不同的事情。
Raku 并非如此。
Raku 中的哈希只是另一个对象。
哈希索引操作只是另一个可以像重载其他运算符一样重载的运算符。
因此您可以创建自己的对象,该对象具有与哈希相同的功能,甚至可以继承它。
class Foo is Hash {
}
class Bar does Associative {
# delegate method calls to a Hash object
has %!hash handles Hash;
}
does Associative
的原因是您可以将其用作支持关联变量的类型。 (Hash 已经具有关联性,因此您也可以继承它。)
my %f is Foo;
my %b is Bar;
要找出您可以编写哪些方法来实现哈希索引操作,您可以查看哈希实现的方法。
因为我们知道自动调用的方法都是大写的,所以我们只需要看一下就可以了。
Hash.^methods.map(*.name).grep(/^<:Lu + [-]>+$/)
# (STORE BIND-KEY WHICH AT-KEY ASSIGN-KEY DELETE-KEY
# DUMP BUILDALL ASSIGN-KEY EXISTS-KEY AT-KEY STORE ACCEPTS BUILDALL)
很明显,以 -KEY
结尾的方法是我们想要编写的方法。 (其他大部分只是对象工件。)
您目前不必编写其中的任何一个来使您的对象类型具有关联性。
如果您不编写特定方法,该功能将无法使用。
class Point does Associative {
has Real ($.x, $.y);
multi method AT-KEY ( 'x' ){ $!x }
multi method AT-KEY ( 'y' ){ $!y }
multi method ASSIGN-KEY ( 'x', Real $new-value ){ $!x = $new-value }
multi method ASSIGN-KEY ( 'y', Real $new-value ){ $!y = $new-value }
multi method EXISTS-KEY ( 'x' --> True ){}
multi method EXISTS-KEY ( 'y' --> True ){}
multi method EXISTS-KEY ( Any --> False ){}
}
my %p is Point;
%p<x> = 1;
%p<y> = 2;
say %p.x; # 1
say %p.y; # 2
请注意,以上内容有一些限制。
一次不能分配给多个属性。
%p< x y > = 1,2;
不能在声明中赋值。
my %p is Point = 1,2;
my %p is Point = x => 1, y => 2;
在多重赋值中,被调用的方法是AT-KEY
。因此,要使其正常工作,必须将其标记为 raw
或 rw
class Point does Associative {
…
multi method AT-KEY ( 'x' ) is rw { $!x }
multi method AT-KEY ( 'y' ) is rw { $!y }
…
}
…
%p<x y> = 1,2;
这处理了多重赋值,但仍将初始化留在声明中。
如果您将属性声明为 is required
,则唯一的写法是:
my %p := Point.new( x => 1, y => 2 );
如果您不这样做,您可以实施 STORE
。
class Point does Associative {
…
method STORE ( \list ) {
($!x,$!y) = list.Hash<x y>
}
}
my %p is Point = x => 1, y => 2;
这也使得您以后也可以分配给它。
%p = x => 3, y => 4;
这可能不是您想要的。
不过我们可以解决这个问题。
只是让它必须有一个 :INITIALIZE
参数。
class Point does Associative {
…
method STORE ( \list, :INITIALIZE($) is required ) {
($!x,$!y) = list.Hash<x y>
}
}
my %p is Point = x => 1, y => 2;
# %p = x => 3, y => 4; # ERROR
在 Point
的情况下,我们可能希望能够用两个元素的列表来声明它:
my %p is Point = 1,2;
或按姓名:
my %p is Point = x => 1, y => 2;
为此,我们可以更改 STORE
的工作方式。
我们将只查看列表中的第一个值并检查它是否是关联的。
如果是,我们将假设所有参数也是关联的。
否则我们将假设它是一个包含两个值的列表,x
和 y
.
class Point does Associative {
…
method STORE ( \list, :INITIALIZE($) is required ) {
if list.head ~~ Associative {
($!x,$!y) = list.Hash<x y>
} else {
($!x,$!y) = list
}
}
}
my %a is Point = x => 1, y => 2;
my %b is Point = 1,2;
Can I define a object that behaves like an hash? That is: if I write $myobject<key>
I endup in a function that I can specify myself?
简短的回答是。不,核心乐没有。但是有一个模块可以让你轻松做到,只需定义 5
方法来创建作为“真实”哈希的完整功能:Hash::Agnostic
较长的答案是:阅读此问题的其他答案:-)
在 Perl 中有 tie
。 Python 支持各种 协议 以便对象可以像字典一样运行。 Raku 有类似的东西吗?
IE。我可以定义一个行为类似于 Hash
的对象吗?那就是:我可以写 $myobject<key>
以结束我自己指定的例程吗?
在 raku
中,语法 <>
似乎是一个后环路运算符,可以通过 AT-KEY
和 EXISTS-KEY
中描述的多方法重载 https://docs.raku.org/language/subscripts#Methods_to_implement_for_associative_subscripting
Perl 在语言中内置了哈希功能。 因此,要扩展它以使对象的行为类似于哈希,您需要告诉运行时做一些不同的事情。
Raku 并非如此。 Raku 中的哈希只是另一个对象。 哈希索引操作只是另一个可以像重载其他运算符一样重载的运算符。
因此您可以创建自己的对象,该对象具有与哈希相同的功能,甚至可以继承它。
class Foo is Hash {
}
class Bar does Associative {
# delegate method calls to a Hash object
has %!hash handles Hash;
}
does Associative
的原因是您可以将其用作支持关联变量的类型。 (Hash 已经具有关联性,因此您也可以继承它。)
my %f is Foo;
my %b is Bar;
要找出您可以编写哪些方法来实现哈希索引操作,您可以查看哈希实现的方法。 因为我们知道自动调用的方法都是大写的,所以我们只需要看一下就可以了。
Hash.^methods.map(*.name).grep(/^<:Lu + [-]>+$/)
# (STORE BIND-KEY WHICH AT-KEY ASSIGN-KEY DELETE-KEY
# DUMP BUILDALL ASSIGN-KEY EXISTS-KEY AT-KEY STORE ACCEPTS BUILDALL)
很明显,以 -KEY
结尾的方法是我们想要编写的方法。 (其他大部分只是对象工件。)
您目前不必编写其中的任何一个来使您的对象类型具有关联性。
如果您不编写特定方法,该功能将无法使用。
class Point does Associative {
has Real ($.x, $.y);
multi method AT-KEY ( 'x' ){ $!x }
multi method AT-KEY ( 'y' ){ $!y }
multi method ASSIGN-KEY ( 'x', Real $new-value ){ $!x = $new-value }
multi method ASSIGN-KEY ( 'y', Real $new-value ){ $!y = $new-value }
multi method EXISTS-KEY ( 'x' --> True ){}
multi method EXISTS-KEY ( 'y' --> True ){}
multi method EXISTS-KEY ( Any --> False ){}
}
my %p is Point;
%p<x> = 1;
%p<y> = 2;
say %p.x; # 1
say %p.y; # 2
请注意,以上内容有一些限制。
一次不能分配给多个属性。
%p< x y > = 1,2;
不能在声明中赋值。
my %p is Point = 1,2; my %p is Point = x => 1, y => 2;
在多重赋值中,被调用的方法是AT-KEY
。因此,要使其正常工作,必须将其标记为 raw
或 rw
class Point does Associative {
…
multi method AT-KEY ( 'x' ) is rw { $!x }
multi method AT-KEY ( 'y' ) is rw { $!y }
…
}
…
%p<x y> = 1,2;
这处理了多重赋值,但仍将初始化留在声明中。
如果您将属性声明为 is required
,则唯一的写法是:
my %p := Point.new( x => 1, y => 2 );
如果您不这样做,您可以实施 STORE
。
class Point does Associative {
…
method STORE ( \list ) {
($!x,$!y) = list.Hash<x y>
}
}
my %p is Point = x => 1, y => 2;
这也使得您以后也可以分配给它。
%p = x => 3, y => 4;
这可能不是您想要的。
不过我们可以解决这个问题。
只是让它必须有一个 :INITIALIZE
参数。
class Point does Associative {
…
method STORE ( \list, :INITIALIZE($) is required ) {
($!x,$!y) = list.Hash<x y>
}
}
my %p is Point = x => 1, y => 2;
# %p = x => 3, y => 4; # ERROR
在 Point
的情况下,我们可能希望能够用两个元素的列表来声明它:
my %p is Point = 1,2;
或按姓名:
my %p is Point = x => 1, y => 2;
为此,我们可以更改 STORE
的工作方式。
我们将只查看列表中的第一个值并检查它是否是关联的。
如果是,我们将假设所有参数也是关联的。
否则我们将假设它是一个包含两个值的列表,x
和 y
.
class Point does Associative {
…
method STORE ( \list, :INITIALIZE($) is required ) {
if list.head ~~ Associative {
($!x,$!y) = list.Hash<x y>
} else {
($!x,$!y) = list
}
}
}
my %a is Point = x => 1, y => 2;
my %b is Point = 1,2;
Can I define a object that behaves like an hash? That is: if I write
$myobject<key>
I endup in a function that I can specify myself?
简短的回答是。不,核心乐没有。但是有一个模块可以让你轻松做到,只需定义 5
方法来创建作为“真实”哈希的完整功能:Hash::Agnostic
较长的答案是:阅读此问题的其他答案:-)