📄 overload.t
字号:
#!./perlBEGIN { chdir 't' if -d 't'; @INC = '../lib';}package Oscalar;use overload ( # Anonymous subroutines:'+' => sub {new Oscalar $ {$_[0]}+$_[1]},'-' => sub {new Oscalar $_[2]? $_[1]-${$_[0]} : ${$_[0]}-$_[1]},'<=>' => sub {new Oscalar $_[2]? $_[1]-${$_[0]} : ${$_[0]}-$_[1]},'cmp' => sub {new Oscalar $_[2]? ($_[1] cmp ${$_[0]}) : (${$_[0]} cmp $_[1])},'*' => sub {new Oscalar ${$_[0]}*$_[1]},'/' => sub {new Oscalar $_[2]? $_[1]/${$_[0]} : ${$_[0]}/$_[1]},'%' => sub {new Oscalar $_[2]? $_[1]%${$_[0]} : ${$_[0]}%$_[1]},'**' => sub {new Oscalar $_[2]? $_[1]**${$_[0]} : ${$_[0]}-$_[1]},qw("" stringify0+ numify) # Order of arguments unsignificant);sub new { my $foo = $_[1]; bless \$foo, $_[0];}sub stringify { "${$_[0]}" }sub numify { 0 + "${$_[0]}" } # Not needed, additional overhead # comparing to direct compilation based on # stringifypackage main;$test = 0;$| = 1;print "1..",&last,"\n";sub test { $test++; if (@_ > 1) { if ($_[0] eq $_[1]) { print "ok $test\n"; } else { print "not ok $test: '$_[0]' ne '$_[1]'\n"; } } else { if (shift) { print "ok $test\n"; } else { print "not ok $test\n"; } }}$a = new Oscalar "087";$b= "$a";# All test numbers in comments are off by 1.# So much for hard-wiring them in :-) To fix this:test(1); # 1test ($b eq $a); # 2test ($b eq "087"); # 3test (ref $a eq "Oscalar"); # 4test ($a eq $a); # 5test ($a eq "087"); # 6$c = $a + 7;test (ref $c eq "Oscalar"); # 7test (!($c eq $a)); # 8test ($c eq "94"); # 9$b=$a;test (ref $a eq "Oscalar"); # 10$b++;test (ref $b eq "Oscalar"); # 11test ( $a eq "087"); # 12test ( $b eq "88"); # 13test (ref $a eq "Oscalar"); # 14$c=$b;$c-=$a;test (ref $c eq "Oscalar"); # 15test ( $a eq "087"); # 16test ( $c eq "1"); # 17test (ref $a eq "Oscalar"); # 18$b=1;$b+=$a;test (ref $b eq "Oscalar"); # 19test ( $a eq "087"); # 20test ( $b eq "88"); # 21test (ref $a eq "Oscalar"); # 22eval q[ package Oscalar; use overload ('++' => sub { $ {$_[0]}++;$_[0] } ) ];$b=$a;test (ref $a eq "Oscalar"); # 23$b++;test (ref $b eq "Oscalar"); # 24test ( $a eq "087"); # 25test ( $b eq "88"); # 26test (ref $a eq "Oscalar"); # 27package Oscalar;$dummy=bless \$dummy; # Now cache of method should be reloadedpackage main;$b=$a;$b++; test (ref $b eq "Oscalar"); # 28test ( $a eq "087"); # 29test ( $b eq "88"); # 30test (ref $a eq "Oscalar"); # 31eval q[package Oscalar; use overload ('++' => sub { $ {$_[0]} += 2; $_[0] } ) ];$b=$a;test (ref $a eq "Oscalar"); # 32$b++;test (ref $b eq "Oscalar"); # 33test ( $a eq "087"); # 34test ( $b eq "88"); # 35test (ref $a eq "Oscalar"); # 36package Oscalar;$dummy=bless \$dummy; # Now cache of method should be reloadedpackage main;$b++; test (ref $b eq "Oscalar"); # 37test ( $a eq "087"); # 38test ( $b eq "90"); # 39test (ref $a eq "Oscalar"); # 40$b=$a;$b++;test (ref $b eq "Oscalar"); # 41test ( $a eq "087"); # 42test ( $b eq "89"); # 43test (ref $a eq "Oscalar"); # 44test ($b? 1:0); # 45eval q[ package Oscalar; use overload ('=' => sub {$main::copies++; package Oscalar; local $new=$ {$_[0]}; bless \$new } ) ];$b=new Oscalar "$a";test (ref $b eq "Oscalar"); # 46test ( $a eq "087"); # 47test ( $b eq "087"); # 48test (ref $a eq "Oscalar"); # 49$b++;test (ref $b eq "Oscalar"); # 50test ( $a eq "087"); # 51test ( $b eq "89"); # 52test (ref $a eq "Oscalar"); # 53test ($copies == 0); # 54$b+=1;test (ref $b eq "Oscalar"); # 55test ( $a eq "087"); # 56test ( $b eq "90"); # 57test (ref $a eq "Oscalar"); # 58test ($copies == 0); # 59$b=$a;$b+=1;test (ref $b eq "Oscalar"); # 60test ( $a eq "087"); # 61test ( $b eq "88"); # 62test (ref $a eq "Oscalar"); # 63test ($copies == 0); # 64$b=$a;$b++;test (ref $b eq "Oscalar") || print ref $b,"=ref(b)\n"; # 65test ( $a eq "087"); # 66test ( $b eq "89"); # 67test (ref $a eq "Oscalar"); # 68test ($copies == 1); # 69eval q[package Oscalar; use overload ('+=' => sub {$ {$_[0]} += 3*$_[1]; $_[0] } ) ];$c=new Oscalar; # Cause rehash$b=$a;$b+=1;test (ref $b eq "Oscalar"); # 70test ( $a eq "087"); # 71test ( $b eq "90"); # 72test (ref $a eq "Oscalar"); # 73test ($copies == 2); # 74$b+=$b;test (ref $b eq "Oscalar"); # 75test ( $b eq "360"); # 76test ($copies == 2); # 77$b=-$b;test (ref $b eq "Oscalar"); # 78test ( $b eq "-360"); # 79test ($copies == 2); # 80$b=abs($b);test (ref $b eq "Oscalar"); # 81test ( $b eq "360"); # 82test ($copies == 2); # 83$b=abs($b);test (ref $b eq "Oscalar"); # 84test ( $b eq "360"); # 85test ($copies == 2); # 86eval q[package Oscalar; use overload ('x' => sub {new Oscalar ( $_[2] ? "_.$_[1]._" x $ {$_[0]} : "_.${$_[0]}._" x $_[1])}) ];$a=new Oscalar "yy";$a x= 3;test ($a eq "_.yy.__.yy.__.yy._"); # 87eval q[package Oscalar; use overload ('.' => sub {new Oscalar ( $_[2] ? "_.$_[1].__.$ {$_[0]}._" : "_.$ {$_[0]}.__.$_[1]._")}) ];$a=new Oscalar "xx";test ("b${a}c" eq "_._.b.__.xx._.__.c._"); # 88# Check inheritance of overloading;{ package OscalarI; @ISA = 'Oscalar';}$aI = new OscalarI "$a";test (ref $aI eq "OscalarI"); # 89test ("$aI" eq "xx"); # 90test ($aI eq "xx"); # 91test ("b${aI}c" eq "_._.b.__.xx._.__.c._"); # 92# Here we test blessing to a package updates hasheval "package Oscalar; no overload '.'";test ("b${a}" eq "_.b.__.xx._"); # 93$x="1";bless \$x, Oscalar;test ("b${a}c" eq "bxxc"); # 94new Oscalar 1;test ("b${a}c" eq "bxxc"); # 95# Negative overloading:$na = eval { ~$a };test($@ =~ /no method found/); # 96# Check AUTOLOADING:*Oscalar::AUTOLOAD = sub { *{"Oscalar::$AUTOLOAD"} = sub {"_!_" . shift() . "_!_"} ; goto &{"Oscalar::$AUTOLOAD"}};eval "package Oscalar; sub comple; use overload '~' => 'comple'";$na = eval { ~$a }; # Hash was not updatedtest($@ =~ /no method found/); # 97bless \$x, Oscalar;$na = eval { ~$a }; # Hash updatedwarn "`$na', $@" if $@;test !$@; # 98test($na eq '_!_xx_!_'); # 99$na = 0;$na = eval { ~$aI }; # Hash was not updatedtest($@ =~ /no method found/); # 100bless \$x, OscalarI;$na = eval { ~$aI };print $@;test !$@; # 101test($na eq '_!_xx_!_'); # 102eval "package Oscalar; sub rshft; use overload '>>' => 'rshft'";$na = eval { $aI >> 1 }; # Hash was not updatedtest($@ =~ /no method found/); # 103bless \$x, OscalarI;$na = 0;$na = eval { $aI >> 1 };print $@;test !$@; # 104test($na eq '_!_xx_!_'); # 105# warn overload::Method($a, '0+'), "\n";test (overload::Method($a, '0+') eq \&Oscalar::numify); # 106test (overload::Method($aI,'0+') eq \&Oscalar::numify); # 107test (overload::Overloaded($aI)); # 108test (!overload::Overloaded('overload')); # 109test (! defined overload::Method($aI, '<<')); # 110test (! defined overload::Method($a, '<')); # 111test (overload::StrVal($aI) =~ /^OscalarI=SCALAR\(0x[\da-fA-F]+\)$/); # 112test (overload::StrVal(\$aI) eq "@{[\$aI]}"); # 113# Check overloading by methods (specified deep in the ISA tree).{ package OscalarII; @ISA = 'OscalarI'; sub Oscalar::lshft {"_<<_" . shift() . "_<<_"} eval "package OscalarI; use overload '<<' => 'lshft', '|' => 'lshft'";}$aaII = "087";$aII = \$aaII;bless $aII, 'OscalarII';bless \$fake, 'OscalarI'; # update the hashtest(($aI | 3) eq '_<<_xx_<<_'); # 114# warn $aII << 3;test(($aII << 3) eq '_<<_087_<<_'); # 115{ BEGIN { $int = 7; overload::constant 'integer' => sub {$int++; shift}; } $out = 2**10;}test($int, 9); # 116test($out, 1024); # 117$foo = 'foo';$foo1 = 'f\'o\\o';{ BEGIN { $q = $qr = 7; overload::constant 'q' => sub {$q++; push @q, shift, ($_[1] || 'none'); shift}, 'qr' => sub {$qr++; push @qr, shift, ($_[1] || 'none'); shift}; } $out = 'foo'; $out1 = 'f\'o\\o'; $out2 = "a\a$foo,\,"; /b\b$foo.\./;}test($out, 'foo'); # 118test($out, $foo); # 119test($out1, 'f\'o\\o'); # 120test($out1, $foo1); # 121test($out2, "a\afoo,\,"); # 122test("@q", "foo q f'o\\\\o q a\\a qq ,\\, qq"); # 123test($q, 11); # 124test("@qr", "b\\b qq .\\. qq"); # 125test($qr, 9); # 126{ $_ = '!<b>!foo!<-.>!'; BEGIN { overload::constant 'q' => sub {push @q1, shift, ($_[1] || 'none'); "_<" . (shift) . ">_"}, 'qr' => sub {push @qr1, shift, ($_[1] || 'none'); "!<" . (shift) . ">!"}; } $out = 'foo'; $out1 = 'f\'o\\o'; $out2 = "a\a$foo,\,"; $res = /b\b$foo.\./; $a = <<EOF;oupsEOF $b = <<'EOF';oups1EOF $c = bareword; m'try it'; s'first part'second part'; s/yet another/tail here/; tr/z-Z/z-Z/;}test($out, '_<foo>_'); # 117test($out1, '_<f\'o\\o>_'); # 128test($out2, "_<a\a>_foo_<,\,>_"); # 129test("@q1", "foo q f'o\\\\o q a\\a qq ,\\, qq oups qq oups1 q second part q tail here s z-Z tr z-Z tr"); # 130test("@qr1", "b\\b qq .\\. qq try it q first part q yet another qq"); # 131test($res, 1); # 132test($a, "_<oups>_"); # 133test($b, "_<oups1>_"); # 134test($c, "bareword"); # 135{ package symbolic; # Primitive symbolic calculator use overload nomethod => \&wrap, '""' => \&str, '0+' => \&num, '=' => \&cpy, '++' => \&inc, '--' => \&dec; sub new { shift; bless ['n', @_] } sub cpy { my $self = shift; bless [@$self], ref $self; } sub inc { $_[0] = bless ['++', $_[0], 1]; } sub dec { $_[0] = bless ['--', $_[0], 1]; } sub wrap { my ($obj, $other, $inv, $meth) = @_; if ($meth eq '++' or $meth eq '--') { @$obj = ($meth, (bless [@$obj]), 1); # Avoid circular reference return $obj; } ($obj, $other) = ($other, $obj) if $inv; bless [$meth, $obj, $other]; } sub str { my ($meth, $a, $b) = @{+shift}; $a = 'u' unless defined $a; if (defined $b) { "[$meth $a $b]"; } else { "[$meth $a]"; } } my %subr = ( 'n' => sub {$_[0]} ); foreach my $op (split " ", $overload::ops{with_assign}) { $subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}"; } my @bins = qw(binary 3way_comparison num_comparison str_comparison); foreach my $op (split " ", "@overload::ops{ @bins }") { $subr{$op} = eval "sub {shift() $op shift()}"; } foreach my $op (split " ", "@overload::ops{qw(unary func)}") { $subr{$op} = eval "sub {$op shift()}"; } $subr{'++'} = $subr{'+'}; $subr{'--'} = $subr{'-'}; sub num { my ($meth, $a, $b) = @{+shift}; my $subr = $subr{$meth} or die "Do not know how to ($meth) in symbolic"; $a = $a->num if ref $a eq __PACKAGE__; $b = $b->num if ref $b eq __PACKAGE__; $subr->($a,$b); } sub TIESCALAR { my $pack = shift; $pack->new(@_) } sub FETCH { shift } sub nop { } # Around a bug sub vars { my $p = shift; tie($_, $p), $_->nop foreach @_; } sub STORE { my $obj = shift;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -