无法在Swift中扩展闭包?

10

在扩展了Bool之后,我感到非常兴奋,我想在Swift中扩展闭包(我们在Smalltalk中做到这一点时没有任何问题,为什么不呢?)。

这是我的播放器:

typealias NiladicClosure = () -> ()

extension NiladicClosure {
    var theAnswerToLife:Int {
        return 42
    }
}

let block:NiladicClosure = {}

block.theAnswerToLife

它无法工作,显示NiladicClosure does not have a member named 'theAnswerToLife'。查看控制台,我得到了更多的信息:

Playground execution failed: /var/folders/2k/6y8rslzn1m95gjpg534j7v8jzr03tz/T/./lldb/33726/playground119.swift:3:1: error: non-nominal type 'NiladicClosure' cannot be extended
extension NiladicClosure {
^         ~~~~~~~~~~~~~~

什么是非名义类型?是否有模式或解决方法?

其他类似的问题早在Swift 2之前就存在了,也足够具体,以至于人们为特定扩展提供了解决方法。我想知道Swift闭包是否是一等对象,我是否可以像在Swift中处理其他东西一样添加附加行为。


1
你不能扩展闭包。请参考https://dev59.com/Cl4c5IYBdhLWcg3wFnA4(该链接是关于扩展元组的,但同样适用于函数/闭包)。 - Martin R
有没有想过为什么元组和闭包不可扩展?在闭包的情况下,是因为闭包从未通过实际对象(或结构体)实例化吗? (至少我看不到它们在哪里这样做) - Travis Griggs
1
@TravisGriggs 这主要是一种实现上的限制。 - Aaron Brager
1个回答

8

什么是非名义类型?

名义类型 是具有显式名称的类型。非名义类型是没有这样的名称的类型,例如 () -> ()。包括闭包和元组(例如 (Int,String))在内的复合类型不能被扩展。

是否有模式/解决方法?

您可以使用组合而不是扩展,也许使用 Swift 2 的新协议功能:

typealias NiladicClosure = () -> ()

protocol NiladicClosureProtocol {
    var someClosure : NiladicClosure? {get}
}

protocol SorryForTheInconvenience {
    var theAnswerToLife : Int {get}
}

extension SorryForTheInconvenience {
    var theAnswerToLife : Int {
        return 42
    }
}

struct SomethingAwesome : NiladicClosureProtocol, SorryForTheInconvenience {
    var someClosure : NiladicClosure?
}

let foo = SomethingAwesome()
foo.theAnswerToLife // 42

你可以使用组合而不是扩展,也许可以利用Swift 2的新协议特性。我不确定这样做会怎么样。我可以创建一个AnswersTheBigQuestion协议,但是我不能扩展non-nominal类型来采用该协议,对吗?因为显然无法对它们进行扩展。 - Travis Griggs
@TravisGriggs 我刚刚添加了一个例子。你可以创建一个包含 NiladicClosure 的结构体,而不是创建一个 NiladicClosure 的东西。 - Aaron Brager
如果SomethingAwesome(或其他实现了NiladicClosureProtocol的对象)能够像真正的闭包一样操作,那将会很好。也就是说,我们可以直接调用foo()而不是foo.someClosure()。在其他语言(C++,Scala,Kotlin等)中,我们可以定义一个`()``操作符,但是Swift不允许这样做。:-( - jcsahnwaldt Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接