首页 > 解决方案 > 其他编程语言上的魔术方法

问题描述

Python 有 , 等方法__add____mul__称为__cmp__魔术方法),它们用作类方法,可以赋予 add( +)、multiplying( *)、compare( ==)、...类的两个实例不同的含义. 我的问题是其他语言有类似的方法吗?我熟悉 Java、C++、ruby 和 PHP,但从未遇到过这样的事情。我知道所有四个都有一个对应于的构造方法__init__,但是其他魔术方法呢?

我尝试在谷歌上搜索“其他编程语言中的魔法方法”,但没有出现任何相关内容,可能它们在不同语言上有不同的名称。

标签: language-agnosticmagic-methods

解决方案


一般来说,一种语言有太多的“魔力”是糟糕的语言设计的标志。也许这就是为什么没有多少语言具有魔术方法的原因?

像这样的魔法创建了一个两类系统:语言设计者可以为语言添加新的魔法方法,但程序员只能使用语言设计大祭司允许他们使用的方法。一般来说,程序员应该可以在不改变语言规范的情况下做尽可能多的事情。

例如,在 Scala 中,+, -, *, /, ==, !=, <, >, <=, >=, ::, |, , &, ||, &&, **, ^, +=, -=, *=,/=等等等等,都是合法的标识符。因此,如果您想为自己的对象实现自己的乘法版本,只需编写一个名为*. 这只是一种无聊的旧标准方法,绝对没有什么“魔法”。

相反,任何方法都可以使用运算符表示法调用,即没有点。任何只接受一个参数的方法都可以在不使用运算符符号的括号的情况下调用。

这不仅适用于方法。此外,任何具有两个类型参数的类型构造函数都可以在中缀表示法中使用,所以如果我有

class ↔️[A, B]

我可以

class Foo extends (String ↔️ Int)

这与

class Foo extends ↔️[String, Int]

好吧……我有点撒谎: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

对于函数的运算符使用,您可以自由定义固定性、关联性和优先级,例如:

infixr 15 <!==!>

在 Ruby 中,有一组预定义的具有相应方法的运算符,例如:

def +(other)
  plus(other)
end

推荐阅读