为什么Perl 6 Str会做位置角色,如何更改[]?

时间:2017-07-25 01:30:31

标签: role perl6 multimethod

我正在玩一个字符串的位置界面。我知道How can I slice a string like Python does in Perl 6?,但我很好奇我是否可以让这件事只是为了咯咯笑。

我想出了这个例子。阅读职位很好,但我不知道如何设置multi来处理任务:

multi postcircumfix:<[ ]> ( Str:D $s, Int:D $n --> Str ) {
    $s.substr: $n, 1
    }
multi postcircumfix:<[ ]> ( Str:D $s, Range:D $r --> Str ) {
    $s.substr: $r.min, $r.max - $r.min + 1
    }
multi postcircumfix:<[ ]> ( Str:D $s, List:D $i --> List ) {
    map( { $s.substr: $_, 1 }, @$i ).list
    }

multi postcircumfix:<[ ]> ( Str:D $s, Int:D $n, *@a --> Str ) is rw {
    put "Calling rw version";
    }


my $string = 'The quick, purple butterfly';

{ # Works
my $single = $string[0];
say $single;
}

{ # Works
my $substring = $string[5..9];
say $substring;
}

{ # Works
my $substring = $string[1,3,5,7];
say $substring;
}

{ # NOPE!
$string[2] = 'Perl';
say $string;
}

最后一个不起作用:

T
uick,
(h   u c)
Index out of range. Is: 2, should be in 0..0
  in block <unit> at substring.p6 line 36

Actually thrown at:
  in block <unit> at substring.p6 line 36
但是,我认为它不会起作用。我不知道应该做什么样的签名或特征来做我想做的事。

为什么[]运算符适用于Str

$ perl6
> "some string"[0]
some string

文档主要暗示[]适用于执行Positional角色的事情,并且那些事情在列表中就像事物一样。来自[] docs in operators

  

用于位置访问@container,a.k.a。&#34;数组索引运算符&#34;的零个或多个元素的通用接口。

Str令人惊讶地发挥了必要的作用,即使它不是@container(据我所知):

> "some string".does( 'Positional' )
True

有没有办法测试某些内容是@container

有没有办法让某些东西列出它的所有角色?

现在,知道字符串可以响应[],我怎样才能找出符合哪个签名?我想知道用于定义我自己的版本的正确签名,以通过[]写入此字符串。

3 个答案:

答案 0 :(得分:7)

实现此目的的一种方法是扩充Str类,因为您实际上只需要覆盖AT-POS方法(Str通常从Any继承) :

use MONKEY;
augment class Str {
    method AT-POS($a) {
        self.substr($a,1)
    }
}
say "abcde"[3]     # d
say "abcde"[^3]    # (a b c)

可在此处找到更多信息:https://docs.perl6.org/language/subscripts#Methods_to_implement_for_positional_subscripting

答案 1 :(得分:3)

要使rw版本正常工作,您首先需要使可能变异的Str rw,并且它需要返回一些反过来也是rw的东西。对于字符串的特定情况,您可以简单地执行:

multi postcircumfix:<[ ]> ( Str:D $s is rw, Int:D $i --> Str ) is rw {
   return $s.substr-rw: $i, 1;
}

通常,您需要一个rw子例程来返回Proxy的实例:

multi postcircumfix:<[ ]> ( Str:D $s is rw, Int:D $i --> Str ) is rw {
   Proxy.new: FETCH => sub { $s.substr: $i },
       STORE => sub -> $newval { $s.substr-rw( $i, 1 ) = $newval }
}

虽然我还没有看到使用它的生产代码,但还有一个return-rw运算符,您偶尔需要它而不是return

sub identity( $x is rw ) is rw { return-rw $x }
identity( my $y ) = 42; # Works, $y is 42.

sub identity-fail( $x is rw ) is rw { return $x }
identity-fail( my $z ) = 42; # Fails: "Cannot assign to a readonly variable or a value"

如果一个函数在没有执行returnreturn-rw或抛出异常的情况下到达终点,则返回最后一个语句的值,并且(当前),它的行为就好像它之前一样return-rw

sub identity2( $x is rw ) is rw { $x }
identity2( my $w ) = 42; # Works, $w is 42.

答案 2 :(得分:1)

这是一个旨在让你这样做的模块:

https://github.com/zoffixznet/perl6-Pythonic-Str

然而:

  

此模块不提供Str.AT-POS或使Str类型为Positional或Iterable角色。后者因核心类型不执行这些角色的固有假设而导致核心和非核心代码的各种后果。这意味着简单的英语是你只能用[...] postcircumfix运算符索引你的字符串,并且不能将它们视为字符列表 - 如果你需要那么只需调用.comb。