Swift 将成员函数快速传递给接受可选闭包的函数

Swift 将成员函数快速传递给接受可选闭包的函数,swift,optional-parameters,Swift,Optional Parameters,我试图构造一个包含可选闭包的表。当我尝试实例化表的一个实例时,为闭包传递一个成员函数,我会得到一个编译错误 从错误消息中,似乎无法将成员函数转换为可选成员函数。我不明白为什么不;Int或其他类型可以很容易地转换为optionals struct Foo { typealias Routine = (_ x: Int) -> Int let int: Int let aRoutine: Routine? init(_ int: Int, _ routine

我试图构造一个包含可选闭包的表。当我尝试实例化表的一个实例时,为闭包传递一个成员函数,我会得到一个编译错误

从错误消息中,似乎无法将成员函数转换为可选成员函数。我不明白为什么不;Int或其他类型可以很容易地转换为optionals

struct Foo {

    typealias Routine = (_ x: Int) -> Int
    let int: Int
    let aRoutine: Routine?

    init(_ int: Int, _ routine: Routine? = nil) {
        self.int = int
        self.aRoutine = routine
    }
}

class Bar {

    let foo = Foo(5, doSomething) // Compile error here

    func doSomething(_ x: Int) -> Int {
        return x
    }
}
无法将类型为“(Bar)->(Int)->Int”的值转换为预期的参数类型“Foo.Routine?”(也称为“可选Int>”)


您刚刚发现成员函数(又称实例方法)是用Swift编写的。看

Foo.doSomething(:)
不仅仅是一个免费函数(也称为全局函数)。它是一个实例方法,可以访问实例,
self
。但是,如果您直接将该方法作为闭包,它不知道
self
的值是什么

有几种选择:

  • 如果
    doSomething(:)
    的实现不需要访问
    self
    ,则可以将其移出
    Foo
    的声明,并将其声明为全局函数

    或者,您可以将其转换为静态函数,方法是将其保持在原来的位置,并使用
    static
    修饰符。与全局函数相比,它还有一个额外的好处,即它通过将代码移动到适当的名称空间来“组织”代码

  • 如果
    doSomething(:)
    的实现确实需要一个实例来操作,那么您可以访问该实例的未应用方法。这里有一个例子。为了演示,我添加了显式类型注释,但通常应该忽略这些注释

    let object: Bar = Bar() // an object of type Bar
    
    let boundDoSomethingMethod: (Int) -> Int = object.doSomething // a bound method which operates on `object`
    
    // alternatively:
    let unboundDoSomethingMethod: (Bar) -> (Int) -> Int = Bar.doSomething
    let boundDoSomethingMethod: (Int) -> Int = unboundDoSomethingMethod(object)
    

  • 您刚刚发现成员函数(又称实例方法)是用Swift编写的。看

    Foo.doSomething(:)
    不仅仅是一个免费函数(也称为全局函数)。它是一个实例方法,可以访问实例,
    self
    。但是,如果您直接将该方法作为闭包,它不知道
    self
    的值是什么

    有几种选择:

  • 如果
    doSomething(:)
    的实现不需要访问
    self
    ,则可以将其移出
    Foo
    的声明,并将其声明为全局函数

    或者,您可以将其转换为静态函数,方法是将其保持在原来的位置,并使用
    static
    修饰符。与全局函数相比,它还有一个额外的好处,即它通过将代码移动到适当的名称空间来“组织”代码

  • 如果
    doSomething(:)
    的实现确实需要一个实例来操作,那么您可以访问该实例的未应用方法。这里有一个例子。为了演示,我添加了显式类型注释,但通常应该忽略这些注释

    let object: Bar = Bar() // an object of type Bar
    
    let boundDoSomethingMethod: (Int) -> Int = object.doSomething // a bound method which operates on `object`
    
    // alternatively:
    let unboundDoSomethingMethod: (Bar) -> (Int) -> Int = Bar.doSomething
    let boundDoSomethingMethod: (Int) -> Int = unboundDoSomethingMethod(object)
    

  • 谢谢你提供的信息。我知道现在发生了什么-没有对象,doSomething是模棱两可的。我在课堂上通过let宣布了这一点。因此,它是在Bar对象实例化之前设置的,因此没有对象。我在Bar的init例程中移动了let foo=foo(5,doSomething),一切都很好。@TroutStalker这样做时,您隐式地引用了
    self.doSomething
    ,它绑定到
    self
    。注意这一点,因为如果将
    foo
    存储在
    Bar
    对象中,并且
    foo
    捕获了
    Bar
    对象,那么最终会出现一个强引用循环和内存泄漏。我没有想到强引用。在这种情况下,这不应该是一个问题,因为它是一个命令行应用程序,并且两个对象在整个过程中都在使用。不过,我以后会记住它。@TroutStalker呃,你永远不会知道当你不小心复制粘贴了一些这样的错误代码,并在你不想要的地方结束了一个强大的保留周期。您想用
    Foo
    解决什么问题?谢谢您提供的信息。我知道现在发生了什么-没有对象,doSomething是模棱两可的。我在课堂上通过let宣布了这一点。因此,它是在Bar对象实例化之前设置的,因此没有对象。我在Bar的init例程中移动了let foo=foo(5,doSomething),一切都很好。@TroutStalker这样做时,您隐式地引用了
    self.doSomething
    ,它绑定到
    self
    。注意这一点,因为如果将
    foo
    存储在
    Bar
    对象中,并且
    foo
    捕获了
    Bar
    对象,那么最终会出现一个强引用循环和内存泄漏。我没有想到强引用。在这种情况下,这不应该是一个问题,因为它是一个命令行应用程序,并且两个对象在整个过程中都在使用。不过,我以后会记住它。@TroutStalker呃,你永远不会知道当你不小心复制粘贴了一些这样的错误代码,并在你不想要的地方结束了一个强大的保留周期。你想用
    Foo
    解决什么问题?