提问者:小点点

代理的多重方法


使用Proxy时,存储方法是否可以使用多调度?在下面的最小示例中,存储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

但是如果给定一个Str,我想以不同的方式处理STORE。我发现的工作(除了使用给定/的巨型方法之外,是在块内创建一个multisub,并返回sub(因为multimethod不能用引用

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

有没有更好的方法来做到这一点(主要是为了使用方法的代码清晰,因为sub感觉…误导)?


共1个答案

匿名用户

关于误导:FETCHSTORE值预期Callables,它可以是方法

回到问题,没有直接的方法可以做到这一点,但有一个更好的间接方法可能更清晰。您可以通过首先设置multisub,然后将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

如果你想让代码更短,但可能不太容易理解,你可以去掉proto(因为它会为你自动生成)和中的sub(因为你可以):

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