5

我正在玩字符串的位置界面。我知道如何像 Python 在 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

文档主要暗示了[]从事位置角色的事物的工作,并且这些事物在列表中,就像事物一样。从[]操作员的文档中

用于对@container 的零个或多个元素进行位置访问的通用接口,也称为“数组索引运算符”。

Str令人惊讶的是,即使它不是@container(据我所知),它也扮演了必要的角色:

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

有没有办法测试某事是一个@container

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

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

4

3 回答 3

8

实现这一点的一种方法是扩充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.raku.org/language/subscripts#Methods_to_implement_for_positional_subscripting

于 2017-07-25T07:57:18.140 回答
4

为了使您的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"

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

sub identity2( $x is rw ) is rw { $x }
identity2( my $w ) = 42; # Works, $w is 42.
于 2017-08-07T04:44:40.350 回答
3

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

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

然而:

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

于 2017-07-31T21:41:09.623 回答