Bab*_*sta -2 language-agnostic magic-methods
Python 有诸如__add__
、__mul__
、__cmp__
等等(称为魔术方法)之类的方法,它们被用作类方法,并且可以赋予加法(+
)、乘法(*
)、比较(==
)……类的两个实例不同的含义. 我的问题是其他语言有类似的方法吗?我熟悉 Java、C++、ruby 和 PHP,但从未遇到过这样的事情。我知道所有四个都有一个对应于 的构造函数方法__init__
,但是其他魔术方法呢?
我尝试在谷歌上搜索“其他编程语言中的魔术方法”,但没有显示任何相关内容,可能它们在不同语言上有不同的名称。
一般来说,语言中的“魔法”太多是语言设计糟糕的标志。也许这就是为什么没有多少语言拥有魔法方法的原因?
像这样的魔法创造了一个两级系统:语言设计者可以向语言添加新的魔法方法,但程序员被限制只能使用语言设计高级牧师允许他们使用的方法。一般来说,程序员应该可以在不需要更改语言规范的情况下做尽可能多的事情。
例如,在 Scala 中,+
, -
, *
, /
, ==
, !=
, <
, >
, <=
, >=
, ::
, |
, &
, ||
, &&
, **
, ^
, +=
, -=
, *=
,/=
等等,只是合法的标识符。因此,如果您想为自己的对象实现自己的乘法版本,只需编写一个名为*
. 这只是一个无聊的旧标准方法,它绝对没有什么“魔法”。
相反,任何方法都可以使用运算符符号调用,即没有点。并且可以在不使用运算符符号的情况下调用任何只接受一个参数的方法。
这不仅适用于方法。此外,任何具有两个类型参数的类型构造函数都可以用于中缀表示法,所以如果我有
class ??[A, B]
Run Code Online (Sandbox Code Playgroud)
我可以
class Foo extends (String ?? Int)
Run Code Online (Sandbox Code Playgroud)
这与
class Foo extends ??[String, Int]
Run Code Online (Sandbox Code Playgroud)
嗯……我有点撒谎:Scala 中有一些语法糖:
foo()
foo.apply()
如果foo
在作用域中没有命名方法,则转换为。这允许您有效地重载函数调用运算符。foo.bar = baz
被翻译成foo.bar_=(baz)
. 这允许您有效地重载属性分配。(这就是你在 Scala 中编写 setter 的方式。)foo(bar) = baz
被翻译成foo.update(bar, baz)
. 这允许您有效地重载索引分配。(例如,这就是您在 Scala 中编写数组或字典访问的方式)。!foo
(和其他几个)被翻译成foo.unary_!
.foo += bar
将尝试调用 的+=
方法foo
,即它等效于foo.+=(bar)
。但是如果这失败并且 foo
是一个有效的左值,并且 foo
有一个名为 的方法+
,那么 Scala 也会尝试foo = foo + bar
。此外,优先级、结合性和固定性在 Scala 中是固定的:它们由方法名称的第一个字符决定。即所有以 开头的方法*
具有相同的优先级,所有以 开头的方法-
具有相同的优先级,以此类推。
Haskell 更进一步:函数和运算符之间没有根本区别。每个函数都可以用于函数调用符号和运算符符号。唯一的区别是词法上的:如果函数名由运算符字符组成,那么当我想在函数调用表示法中使用它时,我必须将它括在括号中。OTOH,如果函数名称由字母数字字符组成,并且我想在运算符表示法中使用它,则需要将它用反引号括起来。因此,以下内容是等效的:
a + b
(+) a b
a `plus` b
plus a b
Run Code Online (Sandbox Code Playgroud)
对于函数的运算符用法,您可以自由定义固定性、结合性和优先级,例如:
a + b
(+) a b
a `plus` b
plus a b
Run Code Online (Sandbox Code Playgroud)
在 Ruby 中,有一组预定义的运算符,它们具有相应的方法,例如:
infixr 15 <!==!>
Run Code Online (Sandbox Code Playgroud)