简体   繁体   English

在Swift中声明函数类型变量有什么意义?

[英]What is the point in declaring a variable of function type in Swift?

在此输入图像描述

I got this from a book, this code was used in a didSet method and I'm confused on why this would be useful when you can just write a function that calls either function slowdown() or function speedup()?? 我从一本书中得到了这个,这个代码用在了didSet方法中,我很困惑为什么当你能编写一个调用函数slowdown()或函数speedup()的函数时这会有用呢? This is basically declaring a "variable function" and "setting it equal to its own definition" which then returns a "function"? 这基本上是声明一个“变量函数”和“将它设置为等于它自己的定义”然后返回一个“函数”? (correct me if I'm wrong). (如我错了请纠正我)。 Why the need to use a variable and set it equal to the definition when I could just create a function? 当我可以创建一个函数时,为什么需要使用变量并将其设置为等于定义? What is the usefulness in that? 那有用的是什么?

When you start to learn about function literals, functions that take and return other functions, and variables that hold functions, all kinds of new patterns open up. 当您开始学习函数文字,获取和返回其他函数的函数以及保存函数的变量时,会打开各种新模式。 This is one of the most powerful tools in programming. 这是编程中最强大的工具之一。

Your description isn't quite correct. 你的描述不太正确。 It's not "setting it equal to its own definition." 它不是“将它设置为与自己的定义相同”。 It's treating functions as values, just like integers, booleans, or structs. 它将函数视为值,就像整数,布尔值或结构一样。 And when you treat a function as a value, you can combine functions, much like you combine other values. 当您将函数视为值时,您可以组合函数,就像组合其他值一样。 And that is incredibly powerful. 这非常强大。

Let's consider just a very basic example based on yours: 让我们考虑一个基于你的基本示例:

var speed = 0
func speedup() { speed++ }
func slowdown() { speed-- }
var changeSpeed = speedup

speed // 0
changeSpeed()
speed // 1

OK great. 太好了。 But as you say, we could have set a bool or something and just done what we wanted to do. 但正如你所说,我们可以设置一个bool或其他东西,只是做了我们想做的事情。 But let's take it further: 但让我们进一步说明:

func twice(f: () -> Void) -> (() -> Void) { return { f(); f() } }

This is a function that takes a function and returns a new function that does the first one twice. 这是一个函数,它接受一个函数并返回一个新函数,它执行第一个函数两次。 Read that again, and think about it. 再读一遍,并考虑一下。 It's a function that takes a function and doubles whatever that function does. 它是一个函数,它接受一个函数,并且无论函数做什么都会加倍。 We don't care what that function is. 我们不关心这个功能是什么。 We can double anything. 我们可以加倍。

So let's double our changing function: 所以让我们改变我们的功能:

changeSpeed = twice(changeSpeed)
changeSpeed()
speed // 3

We didn't have to modify speedup to handle this. 我们没有必要修改speedup来处理这个问题。 twice doesn't care if we pass speedup or slowdown or some other function that we might invent in the future. 如果我们通过speedupslowdown或我们将来可能发明的其他功能, twice不关心。 We have a wide variety of ways we can expand this code without having to rewrite any of the working original code. 我们可以通过各种方式扩展此代码,而无需重写任何正常工作的原始代码。 And we have access to higher-order functions like twice . 我们可以访问twice更高阶的函数。 These are functions that take or return other functions, and they're incredibly powerful. 这些是获取或返回其他功能的功能,它们非常强大。 In Swift, they include things like map and filter , and it's all tied to the ability to create literal functions and assign them to things. 在Swift中,它们包括mapfilter类的东西,它们都与创建文字函数并将它们分配给事物的能力联系在一起。

Let's take this a step further. 让我们更进一步。 Don't worry terribly about all the ideas in this code, just on what it allows us to do. 不要担心这段代码中的所有想法,只关注它允许我们做什么。

import Darwin

var speed = 0
func speedup() { speed++ }
func slowdown() { speed-- }

var changeSpeed: () throws -> () = speedup

// This funny syntax lets us more easily create a function that takes a 
// function and retries it some number of times. It's called "currying".
// But the point is that calling `retry` will create a new function that
// retries the given function.
func retry(n: Int)(_ f: () throws -> Void)() rethrows {
    for _ in 1..<n {
        do {
            try f()
            return
        } catch {
            print("It failed. Let's try it again!")
        }
    }
    // One last try. If it fails, so we do we
    try f()
}

struct FailedError : ErrorType {}

// Similarly, `maybe` takes a function and might choose not to run it
func maybe(p: Float)(_ f: () throws -> ())() throws {
    if Float(arc4random())/Float(INT32_MAX) < p {
        try f()
    } else {
        throw FailedError()
    }
}

// With that, we can create a function called "lotsOfTries" that tries
// other functions 10 times. Yes, we're creating a function with `let`.
let lotsOfTries = retry(10)

// And we can create a function that fails other functions most of the time.
let badChance = maybe(0.15)

// And then we can glue them all together without knowing how they work internally.
changeSpeed = lotsOfTries(badChance(speedup))

do {
    try changeSpeed()
    print(speed)
} catch {
    print("Couldn't do it, sorry")
}

So those are the kinds of functions you can build once you really embrace this kind of coding. 所以,一旦你真正接受这种编码,那些就是你可以构建的功能。 In my own code, I use functions similar to retry because "retry some number of times, but only for certain kinds of errors, and not too many times" is a really complicated problem independent of what's being retried. 在我自己的代码中,我使用类似于retry函数,因为“重试一些次数,但仅针对某些类型的错误,而不是太多次”是一个非常复杂的问题,与正在重试的内容无关。 And I create functions that log calls to other functions, which is really convenient for consistent logging. 我创建了记录其他函数调用的函数,这对于一致的日志记录非常方便。 And I have HTTP request handlers that perform authentication, and then wrap other HTTP request handlers that do proxying that wrap other HTTP request handlers that.... this is how functional composition works, and it can really change how you write programs. 我有一个执行身份验证,然后换行不进行代理那套其他 HTTP请求处理程序....这是怎样构图功能的工作原理其他 HTTP请求处理程序,它可以真正改变你如何编写程序的HTTP请求处理程序。

And also, in the simplest of cases, this lets us do callbacks. 而且,在最简单的情况下,这可以让我们做回调。 So that comes up now and then… 所以这时不时出现......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM