pud*_*dge 13 perl operator-overloading
长话短说:我们想要标记字符串,以便稍后我们可以对它们做一些事情,即使它们嵌入其他字符串中.
所以我们想,嘿,让我们尝试重载.它非常整洁.我可以这样做:
my $str = str::new('<encode this later>');
my $html = "<html>$str</html>";
print $html; # <html><encode this later></html>
print $html->encode; # <html><encode this later></html>
Run Code Online (Sandbox Code Playgroud)
它通过重载连接运算符来创建一个新的对象数组,其中包含普通字符串"<html>",包含"<稍后编码>"的对象和普通字符串"</ html>".它可以任意嵌套这些.在编码时,它将保留纯字符串,但编码对象字符串.但是如果你对对象进行字符串化,那么它只是将它作为普通字符串吐出来.
这很有效,除了在某些情况下,它没有明显的原因.下面的脚本显示了我在5.10到5.22中重复的行为.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper; $Data::Dumper::Sortkeys=1;
my $str1 = str::new('foo');
my $str2 = str::new('bar');
my $good1 = "$str1 $str2";
my $good2;
$good2 = $good1;
my($good3, $good4);
$good3 = "$str1 a";
$good4 = "a $str1";
my($bad1, $bad2, $bad3);
$bad1 = "a $str1 a";
$bad2 = "$str1 $str2";
$bad3 = "a $str1 a $str2 a";
say Dumper { GOOD => [$good1, $good2, $good3], BAD => [$bad1, $bad2, $bad3] };
$bad1 = ''."a $str1 a";
$bad2 = ''."$str1 $str2";
$bad3 = ''."a $str1 a $str2 a";
say Dumper { BAD_GOOD => [$bad1, $bad2, $bad3] };
package str;
use Data::Dumper; $Data::Dumper::Sortkeys=1;
use strict;
use warnings;
use 5.010;
use Scalar::Util 'reftype';
use overload (
'""' => \&stringify,
'.' => \&concat,
);
sub new {
my($value) = @_;
bless((ref $value ? $value : \$value), __PACKAGE__);
}
sub stringify {
my($str) = @_;
#say Dumper { stringify => \@_ };
if (reftype($str) eq 'ARRAY') {
return join '', @$str;
}
else {
$$str;
}
}
sub concat {
my($s1, $s2, $inverted) = @_;
#say Dumper { concat => \@_ };
return new( $inverted ? [$s2, $s1] : [$s1, $s2] );
}
1;
Run Code Online (Sandbox Code Playgroud)
我希望所有这些都被转储为对象,而不是字符串.但是"BAD"的例子都是字符串化的.所有"BAD"示例都是在我分配一个字符串对象时,我正在连接到先前声明的变量.如果我同时声明,或者先前连接字符串,或者添加额外的连接(超出插值字符串concat),那么它可以正常工作.
这很坚果.
脚本的结果:
$VAR1 = {
'BAD' => [
'a foo a',
'foo bar',
'a foo a bar a'
],
'GOOD' => [
bless( [
bless( [
bless( do{\(my $o = 'foo')}, 'str' ),
' '
], 'str' ),
bless( do{\(my $o = 'bar')}, 'str' )
], 'str' ),
$VAR1->{'GOOD'}[0],
bless( [
$VAR1->{'GOOD'}[0][0][0],
' a'
], 'str' )
]
};
$VAR1 = {
'BAD_GOOD' => [
bless( [
'',
bless( [
bless( [
'a ',
bless( do{\(my $o = 'foo')}, 'str' )
], 'str' ),
' a'
], 'str' )
], 'str' ),
bless( [
'',
bless( [
bless( [
$VAR1->{'BAD_GOOD'}[0][1][0][1],
' '
], 'str' ),
bless( do{\(my $o = 'bar')}, 'str' )
], 'str' )
], 'str' ),
bless( [
'',
bless( [
bless( [
bless( [
bless( [
'a ',
$VAR1->{'BAD_GOOD'}[0][1][0][1]
], 'str' ),
' a '
], 'str' ),
$VAR1->{'BAD_GOOD'}[1][1][1]
], 'str' ),
' a'
], 'str' )
], 'str' )
]
};
Run Code Online (Sandbox Code Playgroud)
这种行为对我没有意义.我想了解为什么它以这种方式工作,我想找到一个解决方法.
好吧,这不是一个很好的解决方案,也没有回答为什么 perl 这样做,但我得到了一些东西......我在那里留下了一些调试打印语句。
无论出于何种原因,perl 认为您想要将对对象的标量引用转换为标量字符串。您可以通过添加对引用的引用,然后取消引用它来欺骗它不执行此操作。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper; $Data::Dumper::Sortkeys=1;
use Scalar::Util 'reftype';
my $str1 = str::new('foo');
my $str2 = str::new('bar');
say 'good1';
my $good1 = "$str1 $str2";
say 'g1 ', reftype($good1);
say Dumper $good1;
say 'bad1';
my $bad1;
say 'b1 ', reftype($bad1);
$bad1 = "$str1 $str2";
say 'b2 ', reftype($bad1);
say Dumper $bad1;
say 'workaround';
my $workaround;
say 'w1 ', reftype($workaround);
$workaround = ${\"$str1 $str2"};
say 'w2 ', reftype($workaround);
say Dumper $workaround;
package str;
use Data::Dumper; $Data::Dumper::Sortkeys=1;
use strict;
use warnings;
use 5.010;
use Scalar::Util 'reftype';
use overload (
'""' => \&stringify,
'.' => \&concat,
);
sub new {
my ($value) = @_;
bless((ref $value ? $value : \$value), __PACKAGE__);
}
sub stringify {
my ($str) = @_;
say "stringify";
say reftype($str);
if (reftype($str) eq 'ARRAY') {
say scalar @$str;
return join '', @$str;
}
else {
$$str;
}
}
sub concat {
my ($s1, $s2, $inverted) = @_;
say "concat";
say reftype($s1);
say reftype($s2);
say reftype($inverted);
return new( $inverted ? [$s2, $s1] : [$s1, $s2] );
}
1;
Run Code Online (Sandbox Code Playgroud)
$workaround 为您提供以下内容
$VAR1 = bless( [
bless( [
bless( do{\(my $o = 'foo')}, 'str' ),
' '
], 'str' ),
bless( do{\(my $o = 'bar')}, 'str' )
], 'str' );
Run Code Online (Sandbox Code Playgroud)