【问题标题】:How to pass closure with argument as argument and execute it?如何以参数作为参数传递闭包并执行它?
【发布时间】:2016-11-15 06:41:49
【问题描述】:

A 类的初始化器将可选闭包作为参数:

class A {
   var closure: ()?

   init(closure: closure()?) {
      self.closure = closure
      self.closure()
   }
}

我想传递一个带有参数的函数作为闭包:

class B {
    let a = A(closure: action(1)) // This throws the error: Cannot convert value of type '()' to expected argument type '(() -> Void)?'

    func action(_ i: Int) {
       //...
    }
}

A 应该执行闭包action 和参数i

我不确定如何正确编写此代码,请参阅上面代码注释中的错误。有什么需要改变的?

【问题讨论】:

  • 首先,这不是一个函数类型,它是一个 void 可选。没有太大意义,但无论如何。您要查找的词是部分应用函数。
  • @ValentinRadu “你要找的词是部分应用函数”不,不是。
  • @matt 需要解释一下吗?您有一个部分应用的函数,其中所有参数都部分应用。许多语言都允许这样做,包括 Swift。 func (a:Int)() {}。如果使用它是否有意义,那是另一个问题。
  • @matt 我知道它在语义上不适合。这不再是部分的。尽管如此,它仍然使用相同的语言功能。想想最后一个参数是 void,它也调用了函数。

标签: swift function closures


【解决方案1】:

请让您的“您现在拥有的”代码没有错误。

假设你的班级 A 是这样的:

class A {
    typealias ClosureType = ()->Void

    var closure: ClosureType?

    init(closure: ClosureType?) {
        self.closure = closure
        //`closure` would be used later.
    }

    //To use the closure in class A
    func someMethod() {
        //call the closure
        self.closure?()
    }
}

使用上面给出的A,您需要将您的类B 重写为:

class B {
    private(set) var a: A!
    init() {
        //initialize all instance properties till here
        a = A(closure: {[weak self] in self?.action(1)})
    }

    func action(i: Int) {
        //...
    }
}

【讨论】:

  • 如何在A 类中执行闭包? self.closureself.closure?() 似乎都不起作用。
  • self.closure?() 应该可以工作。你把那个代码放在哪里了?
  • 我的错,我忘了设置self.closure = closure。在这里的代码示例中写了它,但在我的原始代码中忘记了它:-|
  • @Manuel ,我的旧代码进行循环引用。请检查修改后的代码。
【解决方案2】:

问题在于closure()? 不是类型。而()? 是一个类型,但它可能不是你想要的类型。

如果您希望var closure 具有某种函数作为其值,则需要在声明中使用该函数的类型,例如

var closure: (Int) -> Void

同样地,如果你想让init(closure:)作为它的参数某种函数,你需要在声明中使用该函数的类型,例如

init(closure: (Int) -> Void) {

【讨论】:

  • 所以实际上参数不是Int,而是自定义enum。如果我不想在 A 类和 B 类中声明枚举,有什么办法吗?
  • 枚举必须有一个名字,所以在我使用 Int 的地方使用那个名字。类型就是类型。
  • matt:我很抱歉在这里高调你(离题),但我被打败了:如果你有时间,你对我的this question 的评论有什么评论/解释吗? ,关于我认为在switch 语句中的case ... 模式匹配与使用if case ... 的模式匹配之间的等价(我可以发布一个单独的问题,但它非常接近于我评论的问题的剽窃上)。
【解决方案3】:

类型作为参数

在 Swift 中,每个对象都有一个类型。例如,IntString 等可能是您非常熟悉的所有类型。

因此,当您声明一个函数时,应指定任何参数的显式类型(或有时是协议)。

func swallowInt(number: Int) {}

复合类型

Swift 还有一个复合类型的概念。一个例子是元组。元组只是其他类型的集合。

let httpStatusCode: (Int, String) = (404, "Not Found")

一个函数可以很容易地将一个元组作为它的参数:

func swallowStatusCode(statusCode: (Int, String)) {}

另一种复合类型是函数类型。函数类型由参数元组和返回类型组成。所以上面的swallowInt 函数将具有以下函数类型:(Int) -> Void。同样,接收IntString 并返回Bool 的函数将具有以下类型:(Int, String) -> Bool

函数类型作为参数

所以我们可以使用这些概念来重写函数A:

class A {
    var closure: (() -> Void)?

    init(closure: (() -> Void)?) {
        self.closure = closure
        self.closure()
    }
}

然后传递一个参数就是:

func foo(closure: (Int) -> Void) {
    // Execute the closure
    closure(1)
}

【讨论】:

    【解决方案4】:

    我认为您正在尝试的一种方法是使用以下代码:

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            let _  = A.init(){Void in self.action(2)}
        }
    
        func action(i: Int) {
            print(i)
        }
    }
    
    
    class A: NSObject {
        var closure : ()?
    
        init(closure: (()->Void)? = nil) {
            // Notice how this is executed before the  closure
            print("1")
            // Make sure closure isn't nil
            self.closure = closure?()
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-29
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 2017-04-13
      • 2017-03-15
      • 1970-01-01
      相关资源
      最近更新 更多