oracle 快速关闭_快速关闭

oracle 快速关闭

In this tutorial, we’ll be discussing and seeing the usages (why, how and where) of Swift Closure.
It’s noteworthy to mention here that Swift Function is also a form of closure.

在本教程中,我们将讨论并查看Swift Closure的用法(为什么,如何以及在何处)。
值得注意的是, Swift Function也是一种闭包形式。

快速关闭 (Swift Closure)

According to the Apple Documentation, “Closures are self-contained blocks of functionality that can be passed around and used in your code”.

根据Apple文档,“ 闭包是可以包含在您的代码中的独立功能块”。

Closures can capture and store references to any constants and variables from the context in which they are defined.

闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。

The concept of Swift Closure is similar to blocks in C. Closures are nameless functions and without the keyword func.

Swift Closure的概念类似于C中的 。Closures是无名函数,并且没有关键字func

Swift中的关闭形式 (Forms of Closure in Swift)

Closures can take one of the three forms.

闭包可以采用以下三种形式之一。

  1. Global functions

    全局功能
  2. Nested functions

    嵌套函数
  3. Closures expression

    闭包表达

Global and nested functions were discussed at length in the Functions in Swift tutorial.

Swift的《 函数》教程中详细讨论了全局和嵌套函数。

When we mention closures we generally mean the third form i.e. Closure Expressions. Before we get on with the syntax and use cases, let’s look at the benefits that Closures bring to us.

当我们提到闭包时,我们通常指的是第三种形式,即闭包表达式。 在继续讲语法和用例之前,让我们看一下Closures给我们带来的好处。

Swift中闭包的优点 (Advantages of Closures in Swift)

  1. Closures are much less verbose when compared to Functions. Swift can infer the parameter types and return type from the context in which the closure is defined thereby making it convenient to define and pass to a function

    与功能相比,闭包的详细程度要低得多。 Swift可以从定义闭包的上下文中推断参数类型和返回类型,从而方便定义和传递给函数
  2. Swift Closure can be used to capture and store the state of some variable at a particular point in time and use it later(We’ll be discussing this at length later in the tutorial)

    Swift Closure可用于在特定的时间点捕获和存储某些变量的状态,并在以后使用(我们将在本教程稍后详细讨论)
  3. Closures allow us to run a piece of code even after the function has returned

    闭包使我们即使在函数返回后也可以运行一段代码

快速关闭语法 (Swift Closure Syntax)

Let’s recall the syntax of Functions in swift first.

让我们先快速回顾一下函数的语法。

func name(parameters) -> (return type){

//body of function
}

Functions require a func keyword followed by name of function, arguments and return type after ->

函数需要一个func关键字,后跟函数名称,参数和->之后的返回类型

Syntax for Closures is given below.

闭包的语法如下。

{ (parameters)->(return type) in

//body of the closure
 }

Closures are defined within curly braces. The in keyword separates the arguments and return type from the body.

闭合在花括号内定义。 in关键字将参数和返回类型与主体分开。

Like functions, closures can also be referenced as types. Let’s dive into playground in XCode and start coding.

像函数一样,闭包也可以称为类型。 让我们进入XCode的游乐场并开始编码。

将Swift闭包声明为变量 (Declaring Swift Closures as variables)

var myClosure: (ParameterTypes) -> ReturnType

Let’s create a basic function and a closure that’ll print “Hello World”.

让我们创建一个基本函数和一个将打印“ Hello World”的闭包。

func helloWorldFunc()
{
    print("Hello World")
}
var helloWorldClosure = { () -> () in print("Hello World") }

helloWorldFunc() //prints Hello World
helloWorldClosure() //prints Hello World

In the above code, we’ve defined a closure with no parameters and no return type and set it to a variable helloWorldClosure.

在上面的代码中,我们定义了一个没有参数也没有返回类型的闭包,并将其设置为变量helloWorldClosure

Calling the closure is similar to calling a function as shown above.

调用闭包类似于调用函数,如上所示。

Tip 1: If the closure does not return any value or the type can be inferred you can omit the arrow (->) and the return type. We can shorten the above code as shown below.

提示1 :如果闭包不返回任何值或可以推断出类型,则可以省略箭头( -> )和返回类型。 我们可以缩短上面的代码,如下所示。

var helloWorldClosure = { () in print("Hello World") }

Tip 2: If the closure doesn’t require any parameter or can be inferred, remove the argument parenthesis. Now we don’t need the in keyword too. This will further shorten the code as shown below.

提示2 :如果闭包不需要任何参数或可以推断出,请删除参数括号。 现在我们也不需要in关键字。 这将进一步缩短代码,如下所示。

var helloWorldClosure = { print("Hello World") }

We’ve seen one use case now where closures made the code look less verbose compared to a function. Let’s create a closure with parameters and see how it fares when compared to closures.

我们现在已经看到了一个用例,与函数相比,闭包使代码看起来不太冗长。 让我们创建一个带有参数的闭包,并查看与闭包相比的情况。

带参数和返回类型的Swift闭包 (Swift Closures with arguments and return type)

Let’s create a function and closure that accepts two strings, appends them and return.

让我们创建一个函数和闭包,它接受两个字符串,将它们追加并返回。

func appendString(_ a: String, with b: String) -> String
{
    return a + " : " + b
}

print(appendString("Swift", with: "Functions")) //print "Swift : Functions\n"

So far so good. Lets do the same using a closure.

到目前为止,一切都很好。 让我们使用闭包来做同样的事情。

var appendStringClosure  = { (a:String,b:String) -> (String) in return a + " : " + b  }
print(appendStringClosure("Swift", "Closures")) //prints "Swift : Closures\n"

Thanks to type inference as we’d seen earlier, the above closure definition is the same as the following.

由于前面已经提到了类型推断,因此上述闭包定义与以下内容相同。

var appendStringClosure  = { (a:String,b:String) in return a + " : " + b  } // return type inferred

var appendStringClosure : (String, String) -> String  = { (a,b) in return a + " : " + b  } //Closure type declared on the variable itself

var appendStringClosure : (String, String) -> String  = { (a,b) in  a + " : " + b  } // omit return keyword

There’s even a shortened version for the above.

甚至还有上述的简化版本。

Swift allows us to refer to arguments passed to closure using shorthand argument names : $0, $1, $2 etc. for the first, second, third etc. parameters respectively.

Swift允许我们使用速记参数名称分别传递给闭包的参数 :$ 0,$ 1,$ 2等,分别用于第一个,第二个,第三个等参数。

var appendStringClosure : (String, String) -> String  = { $0 + " : " + $1  }
print(appendStringClosure("Swift", "Closures")) //prints "Swift : Closures\n"

Let’s take it one more step ahead:

让我们再向前迈出一步:

var appendStringClosure  = { $0 + " : " + $1 + " " + $2 }
print(appendStringClosure("Swift", "Closures", "Awesome")) //prints "Swift : Closures Awesome\n"

Add as many arguments as you can.

可以添加尽可能多的参数。

Note: It’s recommended to set the closure type.

注意 :建议设置关闭类型。

It’s time to use Closures inside functions.

现在该在函数内部使用闭包了。

函数内部的闭包 (Closures inside Functions)

Let’s create a function that takes a function/closure as parameter.

让我们创建一个以函数/闭包作为参数的函数。

func operationsSq(a: Int, b:Int, myFunction: (Int, Int)->Int)->Int
{
    return myFunction(a,b)
}

This function expects a parameter of type (Int, Int)->Int as the third argument.
Lets pass a function in there as shown below

此函数期望将(Int, Int)->Int类型的参数作为第三个参数。
让我们在其中传递一个函数,如下所示

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

print(operationsSq(a:2,b:2, myFunction: addSquareFunc)) //a^2 + b^2 prints 8

Fair enough. But creating a different function for another operation (let’s say subtracting squares etc) would keep increasing the boilerplate code.

很公平。 但是为另一个操作创建一个不同的函数(例如减去平方等)将继续增加样板代码。

This is where closure comes to our rescue. We’ve defined the following 4 types of expressions that we’ll be passing one by one in the operationsSq function.

这是我们采取救援行动的目的。 我们定义了以下4种类型的表达式,我们将在operationsSq函数中一一传递。

var addSq : (Int, Int) -> Int = {$0*$0 + $1*$1 }
var subtractSq: (Int, Int) -> Int = { $0*$0 - $1*$1 }
var multiplySq: (Int, Int) -> Int = { $0*$0 * $1*$1 }
var divideSq: (Int, Int) -> Int = { ($0*$0) / ($1*$1) }
var remainderSq: (Int, Int) -> Int = { ($0*$0) % ($1*$1) }

print(operationsSq(a:2,b:2, myFunction: addSq)) //prints 8
print(operationsSq(a:4,b:5, myFunction: subtractSq)) //prints -9
print(operationsSq(a:5,b:5, myFunction: multiplySq)) //prints 625
print(operationsSq(a:10,b:5, myFunction: divideSq)) //prints 4
print(operationsSq(a:7,b:5, myFunction: remainderSq)) //prints 24

Much shorter than what we achieved with a function as a parameter. In fact, we can directly pass the closure expressions as shown below and it’ll achieve the same result:

比我们用函数作为参数实现的结果要短得多。 实际上,我们可以直接传递闭包表达式,如下所示,它将获得相同的结果:

operationsSq(a:2,b:2, myFunction: { $0*$0 + $1*$1 })
operationsSq(a:4,b:5, myFunction: { $0*$0 - $1*$1 })
operationsSq(a:5,b:5, myFunction: { $0*$0 * $1*$1 })
operationsSq(a:10,b:5, myFunction: { ($0*$0) / ($1*$1) })
operationsSq(a:7,b:5, myFunction: { ($0*$0) % ($1*$1) })

尾随闭包 (Trailing Closures)

When the closure is being passed as the final argument to a function we can pass it as a trailing closure.

当闭包作为函数的最终参数传递时,我们可以将其作为尾随闭包传递。

A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function.

即使在函数调用的参数后面,也要在函数调用的括号后面写上结尾的闭包。

When you use the trailing closure syntax, you don’t write the argument label for the closure as part of the function call.

使用尾随闭包语法时,不要在函数调用的过程中为闭包编写参数标签。

If closure argument is the sole argument of the function you can remove the function parentheses. Hence the previous closures can be written as the following and it would still function the same way.

如果闭包参数是该函数的唯一参数,则可以删除函数括号。 因此,前面的闭包可以写成下面的样子,并且仍将以相同的方式起作用。

operationsSq(a:2,b:2){ $0*$0 + $1*$1 }

Let’s look at another example where we’ll be adding the sum of exponentials of numbers using closure expressions.

让我们看另一个例子,我们将使用闭包表达式添加数字的指数和。

func sumOfExponentials(from: Int, to: Int, myClosure: (Int) -> Int)->Int
{

    var sum = 0
    for i in from...to{
    
        sum = sum + myClosure(i)
    }
    print(sum)
    return sum

}

//Trailing closures
sumOfExponentials(from:0,to:5){ $0 } //sum of numbers
sumOfExponentials(from:0,to:5){ $0*$0 } //sum of squares
sumOfExponentials(from:0,to:5){ $0*$0*$0 } //sum of cubes

Convert a numbers array to strings array
Another use case of trailing closure is given below.

将数字数组转换为字符串数组
下面给出了尾随闭包的另一个用例。

var numbers = [1,2,3,4,5,6]
print(numbers)

var strings = numbers.map{"\($0)"}
print(strings) //prints ["1", "2", "3", "4", "5", "6"]\n

map is a high order function for transforming an array.

map是用于转换数组的高阶函数。

Sort numbers in descending order using trailing closures

使用结尾闭包以降序对数字进行排序

var randomNumbers = [5,4,10,45,76,11,0,9]

randomNumbers = randomNumbers.sorted{$0>$1}
print(randomNumbers) //"[76, 45, 11, 10, 9, 5, 4, 0]\n"

捕获闭包列表 (Capture Lists in Closures)

By default, closures can capture and store references to any constants and variables from the context in which they are defined (Hence the name closures).

默认情况下,闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用(因此称为闭包)。

Capturing references to variables can cause our closures to behave differently than it’s supposed to. Let’s see this through an example.

捕获对变量的引用可能导致我们的闭包行为与预期的有所不同。 我们来看一个例子。

var x = 0
var myClosure = { print("The value of x at start is \(x)")  }
myClosure() //prints 0 as desired.

So far so good. The above example looks pretty straightforward until we do this:

到目前为止,一切都很好。 在执行此操作之前,上面的示例看起来非常简单:

var x = 0
var myClosure = { print("The value of x at start is \(x)")  }
myClosure() //The value of x at start is 0
x = 5
myClosure() //The value of x at start is 5

Now myClosure was defined and initialized before changing the value of x to 5. Why does it print 5 in the end then?

现在,在将x的值更改为5之前,已定义并初始化myClosure 。为什么它最后会打印5?

The reason is that closure captures the reference (memory address) of x. Any changes made to value at that memory address would be displayed by the closure when it’s invoked.

原因是闭包捕获x的引用(内存地址)。 闭包在调用时将显示对该内存地址上的值所做的任何更改。

To make x behave as a value type instead we need to make use of Capture Lists. Capture Lists is an array [] that holds local copies of the variables. Thereby capturing the variables by value types and NOT reference types.

为了使x表现为值类型,我们需要使用Capture Lists 。 捕获列表是一个数组[] ,用于保存变量的本地副本。 从而按值类型和非引用类型捕获变量。

The array with the local variables is displayed before the in keyword as shown below.

带有局部变量的数组显示在in关键字之前,如下所示。

var x = 0
var myClosure = { [x] in print("The value of x at start is \(x)")  }
myClosure() // The value of x at start is 0
x = 5
myClosure() //The value of x at start is 0

Capturing reference types can be destructive when used in Classes since the closure can hold a strong reference to an instance variable and cause memory leaks. Let’s see an example of this.

在类中使用时,捕获引用类型可能具有破坏性,因为闭包可以保存对实例变量的强引用,并导致内存泄漏。 让我们来看一个例子。

class Person {

    var x: Int
    var myClosure: ()->() = {print("Hey there")}
    init(x: Int)
    {
    self.x = x
    }
    
    func initClosure()
    {
        myClosure = { print("Initial value is not defined yet")}
    }
    
    deinit{
    print("\(self) escaped")
    }
    

}

var a:Person? = Person(x: 0)
a?.initClosure()
a?.x = 5
a?.myClosure()
a = nil

Deinitializers are called automatically, just before instance deallocation takes place. In the above code, it’ll be called when a is set to nil and self doesn’t have any references attached to it.

在实例解除分配发生之前,会自动调用反初始化器。 在上面的代码中,当a设置为nil并且self没有附加任何引用时,它将被调用。

The above code would print:
"Initial value is not defined yet" followed by ” escaped” (“__lldb_expr_26.Person escaped” for me). Awesome there are no memory leaks. Lets set the value inside myClosure to x as shown below:

上面的代码将打印:
"Initial value is not defined yet"后跟“转义”(对我来说是“ __lldb_expr_26.Person转义”)。 很棒,没有内存泄漏。 让我们将myClosure内的值设置为x ,如下所示:

class Person {

    var x: Int
    var myClosure: ()->() = {print("Hey there")}
    init(x: Int)
    {
    self.x = x
    }
    
    func initClosure()
    {
        myClosure = { print("Intial value is \(self.x)")}
    }
    
    deinit{
    print("\(self) escaped")
    }
  
}

var a:Person? = Person(x: 0)
a?.initClosure()
a?.x = 5
a?.myClosure()
a = nil

Whoops! the print statement within deinit is not printed. The closure holds a strong reference to self. This will eventually lead to memory leaks. A remedy for this is to place a weak or unknown reference to self in a capture list inside the closure as seen below.

哎呀! 不打印deinit的print语句。 封闭强烈提及self 。 最终将导致内存泄漏。 对此的一种补救措施是在闭包内部的捕获列表中放置一个对自身的微弱或未知的引用,如下所示。

  • A weak reference is a reference that does not keep a strong hold on the instance it refers to and so does not stop ARC from disposing of the referenced instance.

    弱引用是指不会对其引用的实例保持强烈控制的引用,因此不会阻止ARC处置引用的实例。
  • An unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime.

    无主引用不会对其引用的实例保持强大的控制力。 但是,与弱引用不同,当另一个实例具有相同的生存期或更长的生存期时,将使用无主引用。

The code for capture list with self reference is given below:

具有self参考的捕获列表的代码如下:

class Person {

    var x: Int
    var myClosure: ()->() = {print("Hey there")}
    init(x: Int)
    {
    self.x = x
    }
    
    func initClosure()
    {
        myClosure = {[weak self] in guard let weakSelf = self else { return }
            print("Intial value is \(weakSelf.x)")}
    }
    
    deinit{
    print("\(self) escaped")
    }
    

}

var a:Person? = Person(x: 0)
a?.initClosure()
a?.x = 5
a?.myClosure()
a = nil

No memory leaks with the above code!

上面的代码没有内存泄漏!

逃逸关闭 (Escaping Closures)

There are two other types of closures too:

还有另外两种类型的闭包:

  • An escaping closure is a closure that’s called after the function it was passed to returns. In other words, it outlives the function it was passed to. An escaping closure is generally used in completion handlers since they are called after the function is over.

    转义闭包是在传递给返回的函数之后调用的闭包。 换句话说,它比传递给它的功能更持久。 逸出闭包通常用于完成处理程序,因为它们在函数结束后被调用。
  • A non-escaping closure is a closure that’s called within the function it was passed into, i.e. before it returns. Closures are non-escaping by default

    非转义的闭包是在传递给它的函数内(即返回之前)调用的闭包。 默认情况下,闭包不转义
var completionHandlers: [() -> Void] = []

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)

}
class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure {[weak self] in guard let weakSelf = self else { return }
            weakSelf.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
    
    deinit{
    print("deinitalised")
    }
}

var s:SomeClass? = SomeClass()
s?.doSomething()
print(s?.x ?? -1) //prints 200


completionHandlers.first?()
print(s?.x ?? -1) //prints 100
s = nil

completionHandlers.first() returns and invokes the first element of the array which is an escaping closure. Since we’d set a value type inside it using capture lists, it prints 100.
We’ll be discussing escaping closures at length in a later tutorial.

completeHandlers.first()返回并调用数组的第一个元素,它是一个转义的闭包。 由于我们将使用捕获列表在其中设置值类型,因此它会打印100。
在后面的教程中,我们将详细讨论转义闭包。

Here’s a screenshot from my playground.

swift closure

这是我操场上的截图。

That’s all about closure in swift.

这就是Swift关闭。

翻译自: https://www.journaldev.com/15163/swift-closure

oracle 快速关闭

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值