在perl中更改运算符“+”的含义

时间:2014-04-03 04:26:21

标签: perl

目前" +"在perl中意味着添加,在我的项目中,我们做了很多字符串连接。我知道我们可以和"。"运营商,如:

$x = $a . $b; #will concatenate string $a, and string $b

但" +"感觉更好。不知道是否有魔法使下面的连接。

$x = $a + $b; 

更好的是,如果两个变量($ a,$ b)都是数字,则检查运算符类型,然后执行"添加"在通常意义上,否则,做连接。

我知道在C ++中,可以重载运算符。希望perl中有类似的东西。

感谢。

1 个答案:

答案 0 :(得分:8)

是的,Perl也提供了运营商重载。

package UnintuitiveString;
use Scalar::Util qw/looks_like_number/;

use overload '+'  => \&concat,
             '.'  => \&concat,
             '""' => \&as_string;

# Additionally, the following operators *have* to be overridden
# I suggest you raise an exception if an implementation does not make sense
# - * / % ** << >> x
# <=> cmp
# & | ^ ~
# atan2 cos sin exp log sqrt int
# 0+ bool
# ~~

sub new {
    my ($class, $val) = @_;
    return bless \$val => $class;
}

sub concat {
    my ($self, $other, $swap) = @_;

    # check for append mode
    if (not defined $swap) {
        $$self .= "$other";
        return $self;
    }

    ($self, $other) = ($other, $self) if $swap;
    return UnintuitiveString->new("$self" . "$other");
}

sub as_string {
    my ($self) = @_;
    return $$self;
}

sub as_number {
    my ($self) = @_;
    return 0+$$self if looks_like_number $$self;
    return undef;
}

现在我们可以做一些奇怪的事情:

my $foo = UnintuitiveString->new(4);
my $bar = UnintuitiveString->new(2);
print $foo + $bar, "\n";  # "42"
my ($num_x, $num_y) = map { $_->as_number } $foo, $bar;
print $num_x + $num_y, "\n"; # "6"
$foo += 6;
print $foo + "\n"; # "46"

但仅仅因为我们可以做这些事情并不意味着我们应该:

  • Perl已经有一个连接运算符:.。使用它完全没问题。

  • 运营商超载会带来巨大的性能损失。之前在perl的VM中使用单个操作码的是现在的一系列方法调用和中间副本。

  • 对于真正了解Perl的人来说,改变运营商的意义是非常困惑的。我在上面的测试用例中偶然发现了几次,当我感到惊讶时$foo + 6不会产生10

  • Perl的标量不是数字字符串,它们同时 并且被解释为一个或另一个取决于在他们的使用上下文。这实际上是半真实的,并且标量具有不同的表示。它们可以是字符串(PV),整数(IV),浮点数(NV)。然而,一旦在诸如加法的数值上下文中使用PV,则确定数值并将其与字符串一起保存,并且我们得到PVIV或PVNV。反之亦然:当在一个字符串上下文中使用数字时,格式化的字符串将与数字一起保存。上面提到的looks_like_number函数确定给定字符串是否可以表示有效数字,例如"42""NaN"。因为在某些上下文中只使用使用标量可以更改表示形式,所以检查给定标量是否为PV并不能保证它是一个字符串,并且IV不保证它是预期的是一个整数。

  • Perl有两组运算符是有充分理由的:如果标量的“类型”是流动的,我们需要另一种方法来明确请求某些行为。例如。 Perl具有数字比较运算符< <= == != >= > <=>和字符串比较运算符lt le eq ne ge gt cmp,其行为可能非常不同:4 XXX 12 -1 <=>(因为4在数值上小于{1}} 12),但1cmp(因为在大多数整理顺序中4比1晚。)

    其他语言因运营商将其操作数强制转换为所需类型而不提供两组运营商而受到很大影响。例如。在Java中,+被重载为连接字符串。然而,这导致了交换性和相关性的丧失。给定三个值x, y, z,可以是字符串或数字,我们会得到不同的结果:

    • x + yy + x - 字符串连接不可交换,而数字加法则是。
    • (x + y) + zx + (y + z) - 只要一个字符串进入比赛场地,+就不会关联。考虑x = 1, y = 2, z = "4"。然后,第一个评估订单将导向"34",而第二个导致"124"

    在Java中,这不是问题,因为语言是静态类型的,并且因为很少有强制(自动装箱,自动装箱,扩展转换和连接中的字符串化)。但是,JavaScript(动态类型并将执行从字符串到其他运算符的数字的转换)显示完全相同的行为。糟糕。

停止这种疯狂。现在。 Perl的运算符集(除了smartmatch)是语言中设计最好的部分之一(其类型系统是现代观点中最差的部分之一)。如果您不喜欢Perl因为它的运算符有意义,那么您可以自由地使用PHP(顺便说一下,它还使用.进行连接以避免此类问题):P