cod*_*ons 6 types hashmap typechecking raku
我欣赏不可变数据结构的价值,真的很喜欢 Raku 内置了很多。我特别喜欢编译器/类型检查器会为我强制执行不变性——我可能有休息日或对某些事情粗心大意,但编译器永远不会.
或者至少,我是这么想的。
然而,我很惊讶地看到以下代码在没有从类型检查器中窥视的情况下运行:
my Map $m = Hash.new('key', 'value');
say $m.WHAT # OUTPUT: «(Hash)»
Run Code Online (Sandbox Code Playgroud)
咨询文件后,我看到Map
是一个父类Hash
(因此Hash.isa('Map')
回报True
所以,我明白了。如何(在机械水平),其typechecks成功,但我留下了两个问题:第一,为什么不继承工作这样的, , 其次,如果我真的希望类型检查器保证我的不可变变量保持这种状态,我该怎么办。
关于“为什么”的问题——像这样构建的地图有什么不同?乐的其他稳定的类型都不是:Set.isa('SetHash')
,Mix.isa('MixHash')
,Bag.isa('BagHash')
,Blob.isa('Buf')
,和(如果计算)List.isa('Array')
所有返回False
。[编辑:正如jjmerelo在下面指出的那样,我颠倒了所有这些。我应该说SetHash.isa('Set')
,MixHash.isa('Mix')
,BagHash.isa('Bag')
和Buf.isa('Blob')
所有的回报False
。有趣的是,Array.isa('List')
returnsTrue
为 Elizabeth Mattijsen 的声明提供了一些支持,即这是一个历史疏忽——sList
和Map
s 绝对是比大多数其他不可变类型更基本的数据类型。]
什么是关于不同Map
S和Hash
ES,他们有这样的行为?
关于更实际的问题,我能做些什么来让类型检查器在这里帮助我更多吗?我知道,在这种特定情况下,我可以写一些类似的东西
my Map $m where { .WHAT === Map } = Hash.new('key', 0); # Throws the error I wanted
Run Code Online (Sandbox Code Playgroud)
甚至
subset MapForRealThisTime of Map where { .WHAT === Map }
Run Code Online (Sandbox Code Playgroud)
这些真的是最好的选择吗?他们都觉得有点笨拙(并且where
块可能有运行时成本?)但也许这是最好的方法?
更一般地说,我真正想要的是一种在严格模式下进行类型检查的方法,可以这么说。如果我显式声明一个变量的类型,我真的希望编译器保证该变量具有那个确切的类型——而不是其他一些恰好将该类型作为父类型的类型。有没有我可以采取的更通用的方法,或者我只是要求 Raku 不会提供的严格程度?
Maps 和 Hashes 的这种行为有何不同?
就我个人而言,我认为这是一个历史性的疏忽,需要在未来的某个时候修复。
这些真的是最好的选择吗?
我认为您正在寻找is
这种情况下的特征:
my %m is Map = a => 42, b => 666;
dd %m; # Map.new((:a(42),:b(666)))
%m<a> = 666; # Cannot change key 'a' in an immutable Map
%m<c> = 666; # Cannot add key 'c' to an immutable Map
Run Code Online (Sandbox Code Playgroud)
我只是要求 Raku 不会提供的严格程度吗
恐怕你是。=:=
您可以在子句中使用运算where
符:
subset RealMap of Map where .WHAT =:= Map;
my RealMap $m = Map.new((a => 42)); # works
my RealMap $h = Hash.new((a => 42));
# Type check failed in assignment to $m; expected RealMap but got Hash ({:a(42)})
Run Code Online (Sandbox Code Playgroud)