还有其他语言有类似Swift的扩展吗?

hgi*_*sel 5 methods member-functions swift swift-extensions

在Swift中,扩展是一种在事后定义类成员的方法.或者,你可以说,它是(来自一个全新的)组合函数的奇特方式:

extension Double {
    var mm: Double { return self * 1_000.0 }
    func mm1() -> Double { return self * 1_000.0 }
}

func mm(a: Double) -> Double {
    return a * 1_000.0
}

print("One meter is \(1.mm) milimeters")
print("One meter is \(1.mm1()) milimeters")
print("One meter is \(mm(1)) milimeters")
Run Code Online (Sandbox Code Playgroud)

我从来没有见过这样的东西.在任何其他语言中都有这样的东西吗?

gma*_*man 5

是的,其他语言也有扩展等功能。正如 @hnh 指出的,C# 具有非常相似的功能

它还清楚地表明此功能不是猴子修补”

扩展方法是一种特殊的静态方法,但它们的调用方式就像扩展类型上的实例方法一样。

换句话说,扩展更像是语法糖。鉴于问题中的示例 Double,您可以创建一个采用 Double 的函数(如问题中所示)

func mm(a: Double) -> Double {
    return a * 1_000.0
}
Run Code Online (Sandbox Code Playgroud)

然后就可以直接调用了

var foo = 12.34;
print("One meter is \(mm(foo)) millimeters")
Run Code Online (Sandbox Code Playgroud)

C# 和 Swift 中的扩展实际上会发生什么,扩展告诉编译器在幕后进行翻译

someDouble.mm()
Run Code Online (Sandbox Code Playgroud)

进入

mm(someDouble)
Run Code Online (Sandbox Code Playgroud)

或者在我们的例子中更像

__extension_for_type_Double_mm(someDouble as self)
Run Code Online (Sandbox Code Playgroud)

所以,没有任何补丁。

这也意味着您可以拥有来自不同模块的多个mm扩展名,并通过仅在该文件中导入该模块来选择每个文件使用哪个扩展名,而其他文件可以导入具有相同类型、同名的另一个扩展名的另一个模块。这对于猴子修补来说是不可能的,因为对象或其类/原型被修补(实际上发生了一些变化)。在这里,没有任何变化,它只是调用独立函数的语法糖。

这意味着 Ruby 和 JavaScript 中的猴子补丁等功能与扩展不同。


tex*_*uce 0

这称为猴子补丁。还有一些其他语言支持它,例如 Ruby

  • 我非常怀疑有人会认为 Swift 扩展是猴子补丁。它们是独立的扩展,除非您将定义它们的模块导入到编译单元中,否则它们甚至不会生效。这与 JavaScript、ObjC 和 Ruby 中的猴子补丁完全不同。 (7认同)
  • @hnh我认为是否被孤立不会改变定义。它看起来像猴子,工作起来像猴子,那么它就是猴子 (2认同)
  • 它可能是一只猴子,但关键是它不是补丁;-) 我想说猴子补丁的关键方面是修改语言的动态运行时来替换或添加方法。例如,您重新定义 JS 对象的键与新函数的绑定,或者通过 ObjC 中的方法混合来执行类似的操作。Swift 扩展完全不是这样的。没有任何东西被修补,一切都干净地分开,没有胡闹。 (2认同)