为什么 Perl 6 Str 扮演位置角色,我如何更改 []?

Why does a Perl 6 Str do the Positional role, and how can I change []?

我正在研究字符串的位置接口。我知道 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

虽然我不认为它会起作用。我不知道它应该有什么签名或特征来做我想做的事。

为什么 [] operator work on a Str?

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

文档主要暗示 [] 可以处理 Positional roles and that those things are in list like things. From the [] docs in operators:

Universal interface for positional access to zero or more elements of a @container, a.k.a. "array indexing operator".

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

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

有没有办法测试某物是 @container

有没有办法让某物列出其所有角色?

现在,知道字符串可以响应 [],我怎样才能确定哪个签名会匹配它?我想知道用于定义我自己的版本以通过 [].

写入此字符串的正确签名

实现此目的的一种方法是扩充 Str class,因为您实际上只需要重写 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.raku.org/language/subscripts#Methods_to_implement_for_positional_subscripting

有一个模块旨在让您执行此操作:

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

但是:

This module does not provide Str.AT-POS or make Str type do Positional or Iterable roles. The latter causes all sorts of fallout with core and non-core code due to inherent assumptions that Str type does not do those roles. What this means in plain English is you can only index your strings with [...] postcircumfix operator and can't willy-nilly treat them as lists of characters—simply call .comb if you need that.`

为了使您的 rw 版本正常工作,您首先需要制作可能也会发生变异的 Str rw,并且它需要 return 反过来也是rw。对于字符串的特定情况,您可以简单地执行:

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

通常,您需要一个 rw 子例程到 return 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 或抛出异常就到达了结尾,最后一条语句的值是 returned,并且(目前),这就像在 return-rw.

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