代理多重方法

use*_*601 5 raku

使用代理时是否可以对存储方法使用multidispatch?在以下最小示例中,在存储Int

my $foo := do {
  my $bar = 1;
  Proxy.new:
    :FETCH( method { return $bar} ),
    :STORE( method (Int $i) { $bar = $i } )
}

say $foo;   # 1
$foo = 2;
say $foo;   # 2
$foo = "3"; # error, need to pass an Int
Run Code Online (Sandbox Code Playgroud)

但是,STORE如果给定一个,我想以不同的方式处理Str。我发现的解决方法(除了使用given/ 进行mega方法之外,wheremulti sub在块内部创建一个,并使用第一个虚拟参数返回子(因为multi method不能用来引用&foo):

my $foo := do {
  my $bar = 1;
  Proxy.new:
    :FETCH( method { return $bar} ),
    :STORE( 
      do { 
        multi sub xyzzy ($, Int $i) { $bar = $i }
        multi sub xyzzy ($, Str $i) { $bar = +$i + 1}
        &xyzzy
      }
    )
}

say $foo;   # 1
$foo = 2;   
say $foo;   # 2
$foo = "3"; 
say $foo;   # 4
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法(主要是为了使代码清晰,method因为sub感觉...误导)?

Eli*_*sen 6

关于误导性:FETCHSTORE期望值Callables,可以是a method或a sub

回到问题,没有直接的方法可以这样做,但是有一种更好的间接方法可能会更清楚。您可以通过设置第multi sub一个,然后将proto作为参数传递来进行此操作:

proto sub store(|) {*}
multi sub store(\self, Int) { say "Int" }
multi sub store(\self, Str) { say "Str" }

my $a := Proxy.new(
  FETCH => -> $ { 42 },
  STORE => &store,
);

say $a;     # 42
$a = 42;    # Int
$a = "foo"; # Str
Run Code Online (Sandbox Code Playgroud)

而且,如果您想使代码更简短,但可能难以理解,则可以摆脱proto(因为它将为您自动生成)和sub中的multi(因为您可以):

multi store(\self, Int) { say "Int" }
multi store(\self, Str) { say "Str" }

my $a := Proxy.new(
  FETCH => -> $ { 42 },
  STORE => &store,
);

say $a;     # 42
$a = 42;    # Int
$a = "foo"; # Str
Run Code Online (Sandbox Code Playgroud)