在我的Str子类中处理"Cannot modify a immutable"



我有这个类,它是Str:的子类

use Vimwiki::File::TextProcessingClasses;
unit class Vimwiki::File::ContentStr is Str;
method new(Str:D $string) {
self.Str::new(value => $string);
}
# this method fails
method capitalize-headers() {
self = Vimwiki::File::TextProcessingClasses::HeadlineCapitalizer.new.capitalize-headers(self);
}

问题是capitalize-headers方法失败并出现Cannot modify an immutable错误,因为它是一个字符串。我可以避免这个问题的一种方法是简单地不将Str子类化,并为我想要使用的Str方法编写包装器,如下所示:

unit class Vimwiki::File::ContentStr;
has Str $!content;
method uc() {
$!content = $!content.uc; 
}

但这让我想知道,Raku中是否有类似AUTOLOAD的东西,而不是编写这些包装器方法,这样,如果一个方法不存在,那么不存在的方法可以默认为在$!content属性上调用。

这可能吗?或者有没有一种更干净的方法来解决不可变对象问题?

Str类型是不可变的。当你写:

my $x = "string";
$x = "another string";

它之所以有效,是因为$x是一个Scalar容器。您并没有更改Str,只是安排$x引用不同的Str。在Raku标准库中,Str是不可变的,这一点在所有地方都是依赖的,所以即使你要以某种方式创建一个可变的子类,你也不太可能!

此外,CCD_ 14也总是不可变的。你可以这样做:

class SubStr is Str {
method capitalize-inplace($self is rw:) {
$self .= uc
}
}

并按如下方式使用:

my $x = SubStr.new(value => "hi");
$x.capitalize-inplace;
say $x

这也是对Scalar容器$x进行更改,并将值为HI的新SubStr实例放入其中

SubStr.new(value => "hi").capitalize-inplace

将死亡:

Parameter '$self' expects a writable container (variable) as an
argument, but got 'hi' (SubStr) as a value without a container.
in method capitalize-inplace at -e line 1
in block <unit> at -e line 1

因此,如果您想要一个围绕Str的可变包装器,那么您实际上必须使用组合,而不是继承。

但这让我想知道,Raku中是否有类似AUTOLOAD的东西,而不是编写这些包装器方法,这样,如果一个方法不存在,那么不存在的方法可以默认为在$!内容属性。

这就是FALLBACK方法。(还有handles特性,但这不是你想要的,因为我想你希望保留包装。(

好吧,这是完成任务的代码:

use Vimwiki::File::TextProcessingClasses;
unit class Vimwiki::File::ContentStr;
has Str $.content;
method FALLBACK ($name) {
my $content = $!content;
$content."$name"();
}
submethod BUILD (:$content) {
$!content = $content;
};
method new( Str:D $content ) {
self.bless( :$content );
}
method capitalize-headers() {
$!content = Vimwiki::File::TextProcessingClasses::HeadlineCapitalizer.new.capitalize-headers($!content);
}

相关内容

最新更新