如果我们可以简单地调用函数来实现,为什么要将函数作为参数传递给其他函数呢?

时间:2019-01-23 11:28:25

标签: swift function methods

我无法理解添加此功能的意义所在。

将作为参数传递或由另一种方法调用的方法

func add(_ a : Int, _ b : Int) -> Int {
    return a + b 
}

从其他函数调用函数时

func average(_ a : Int, _ b : Int) -> Int{
    return add(a, b) / 2
}

将函数作为其他函数的参数传递时

func averageArg(_ plus: (Int, Int) -> Int, _ a: Int, _ b : Int) -> Int {
    return plus(a, b) / 2
}

4 个答案:

答案 0 :(得分:0)

例如,如果没有函数“ postProcess”作为参数,则必须实现树函数:getAndAddData,getAndSubData和getAndMulData。

func add(_ a:Int, _ b:Int) -> Int {
    return a + b
}

func sub(_ a:Int, _  b:Int) -> Int{
    return a - b
}

func mul(_ a:Int, _  b:Int) -> Int{
    return a * b
}

func getAndProcessData(_ postProcess:(Int, Int) -> Int, _ a:Int, _ b:Int) -> Int {

    let a2 = ExampleClass.get(a)
    let b2 = ExampleClass.get(b)
    return postProcess(a2, b2)
}

func exampleFunc(a:Int, b:Int) {

    let getAndAdd = self.getAndProcessData(self.add(_:_:), a, b)
    let getAndSub = self.getAndProcessData(self.sub(_:_:), a, b)
    let getAndMul = self.getAndProcessData(self.mul(_:_:), a, b)
}

答案 1 :(得分:0)

将函数用作参数的原因是它使函数更加灵活。通过传递将两个plus值组合在一起的函数或闭包以返回Int值,调用方可以决定Int的作用。

例如,假设呼叫者希望plus乘以值:

print(averageArg(*, 5, 6))
15

或采用两个值的max(通过闭包):

print(averageArg({ max($0, $1) }, 1, 100))
50

一个更好的例子是Swift函数sorted(by:)sorted进行闭包,该闭包确定areInIncreasingOrder的含义。这样,您只需更改传递的函数即可对数组进行升序和降序排序:

[1, 3, 2, 4].sorted(by: <)
[1, 2, 3, 4]
[1, 3, 2, 4].sorted(by: >)
[4, 3, 2, 1]

以下是使用函数的示例:

func shortNamesFirst(_ name1: String, _ name2: String) -> Bool {
    if name1.count < name2.count {
        return true
    } else if name1.count > name2.count {
        return false
    } else {
        // when names are the same length, sort
        // them alphabetically
        return name1 < name2
    }
}

["Chuck", "Bob", "Bill", "Jo", "Ed", "Alexander"].sorted(by: shortNamesFirst)
["Ed", "Jo", "Bob", "Bill", "Chuck", "Alexander"]

sorted的作者不必为用户可能想要的每种订购提供不同版本的sorted。用户可以决定sorted对他们的意义。

答案 2 :(得分:0)

您的示例并不是非常有说服力的使用传递闭包。但是,假设实现是可变的,即。您不知道在某些情况下会发生什么,使用闭包处理是一个很大的好处。举个例子:

func doSomething(with: AnyObject, whenFails failureClosure: ((Error) -> Void)? = nil) {
  var error: Error?

  // do stuff, maybe setting the error to something...

  if let error = error,
     let failureClosure = failureClosure {
         failureClosure(error)
  }
}

这允许调用者进行doSomething,但通过传递闭包以自定义方式处理函数的失败。

这在异步情况下非常有用,在异步情况下,函数的结果用于执行某些操作,但无法在同一线程(例如,网络调用)中运行执行。

func doSomethingAsynchronously(completion completionClosure: (() -> Void)? = nil) {
   // Do asynchronous stuff

   if let completionClosure = completionClosure {
      completionClosure()
   }
}

答案 3 :(得分:0)

这是一个不经常使用的快速功能,但有时会非常方便。在您的示例中,这确实没有任何意义,但是让我们找到一个实际可行的方案。

首先让我们看看_ plus: (Int, Int) -> Int的含义。该段代码意味着您的函数averageArg接受任何接受两个整数参数并提供整数作为输出的 closure function 。由于add(...)符合此要求(两个integer自变量,并提供integer作为输出),因此您可以将其作为自变量传递。

但是让我们看一个这样的参数有意义的示例。可以说,我们正在为显示酒店评论的应用程序编写前端代码。在此应用程序中,我们需要在某处编写函数fetchReviews(_ serverResponse: ([Review]) -> Void),该函数可从某个远程服务器获取所有酒店评论:

struct Review {
    let author: String
    let rating: Int
}

func fetchReviews(_ completionHandler: @escaping ([Review]) -> Void) {
    // Lets do a request to the server on a separate thread, so that the user can keep
    // interacting with the app. The app doesn't freeze.
    // Making qos .userInitiated will ensure that user interaction will be more important than
    // our backend request.
    DispatchQueue.global(qos: .userInitiated).async {
        // Do some request to the server....

        //...

        // Lets pretend we have received a response, and we are turning the response into an array of reviews
        completionHandler([Review]())
    }
}

因为在服务器响应并给出所有评论之间以及调用fetchReviews之间可能会有(有时很长)延迟,如果应用程序只是冻结,这对用户来说就不好了。相反,您可以在单独的线程上向服务器发出请求,以便用户可以继续使用该应用程序,并且该应用程序不会冻结(请参阅DispatchQueue.global部分)。

但是,一旦我们收到服务器的回复,我们仍然希望向用户显示所有评论。通过添加_ serverResponse参数,我们可以在实际上收到服务器的响应后立即通知调用fetchReviews的任何人。这样,用户可以继续与该应用进行交互,一旦评论可用,我们就可以向用户显示评论!