使用赋值运算符时“方法'ASSIGN-KEY'的调用者必须是对象实例”

dax*_*xim 10 raku

使用键入的键进行哈希...

use v6;
class Foo {}
my Hash[Foo, Foo] $MAP;

my $f1 = Foo.new;
my $f2 = Foo.new;

$MAP{$f1} = $f2;
Run Code Online (Sandbox Code Playgroud)

产生错误:

方法“ASSIGN-KEY”的调用者必须是“Hash[Foo,Foo]”类型的对象实例,而不是“Hash[Foo,Foo]”类型的类型对象。你忘记了'.new'吗?

我觉得它具有误导性;真正的错误是什么,我必须写什么?

我已经尝试过%哈希变量的符号,这也不起作用。

jjm*_*elo 7

按照您定义的方式,$MAP它实际上是一个角色。您需要实例化(实际上是双关语)它:

class Foo {}
my Hash[Foo, Foo] $MAP;

my $map = $MAP.new;

my $f1 = Foo.new;
my $f2 = Foo.new;

$map{$f1} = $f2;
say $map;
Run Code Online (Sandbox Code Playgroud)

这里的死赠品是类不能参数化,角色可以。

还:

say $MAP.DEFINITE; # False
say $map.DEFINITE; # True
Run Code Online (Sandbox Code Playgroud)

但实际上,错误消息非常有用,直到并包括使用 的建议.new,就像我在这里所做的那样。

我们可以将其缩短为:

class Foo {}
my %map = Hash[Foo, Foo].new ;
%map{Foo.new} = Foo.new;
%map.say;
Run Code Online (Sandbox Code Playgroud)

通过根据定义进行双关语,我们不需要 $MAP 中间类。


rai*_*iph 6

TL; JJ博士的回答是正确的,但解释让我感到困惑。我目前将您显示的问题视为自动激活错误/错误和/或 LTA 错误消息。

say my Any       $Any;        # (Any)
say my Hash      $Hash;       # (Hash)
say my Hash[Int] $Hash-Int;   # (Hash[Int])
$Any<a>          = 42;        # OK
$Hash<a>         = 42;        # OK
$Hash-Int.new<a> = 42;        # OK
$Hash-Int<a>     = 42;        # must be an object instance, not a type object
Run Code Online (Sandbox Code Playgroud)

Imo 这是一个错误或非常接近一个错误。

在同一场景中,一个错误/问题也适用于数组:

say my Any       $Any;        # (Any)
say my Array     $Array;      # (Array)
say my Array[Int] $Array-Int; # (Array[Int])
$Any[42]           = 42;      # OK
$Array[42]         = 42;      # OK
$Array-Int.new[42] = 42;      # OK
$Array-Int[42]     = 42;      # Type check failed ... expected Array[Int] but got Array
Run Code Online (Sandbox Code Playgroud)

如果最好将其视为 notabug,那么也许应该更改错误消息。虽然我同意 JJ 的错误消息实际上是正确的(当您了解 raku 的工作原理并弄清楚发生了什么时),但我认为如果我们不将 raku(do) 更改为 dwim,它仍然是 LTA 错误消息。

在抓手方面,我不清楚如何最好地改进错误消息。现在我们有了这个 SO。(参见我在最近写的一个回答错误消息 LTA观点。)

另一种解决方案

我已经尝试过%哈希变量的符号,这也不起作用。

JJ 提供了一个使用显式.new. 但这会降低变量的约束。要保留它:

class Foo {}
constant FooFoo = Hash[Foo:D,Foo:D];
my %foo is FooFoo;
%foo{Foo.new} = Foo.new;
Run Code Online (Sandbox Code Playgroud)

理想情况下constant不需要,也许有一天它不需要,但我认为特征解析是有限的。