在函数中使用swift闭包作为参数时,是否可以将其设置为默认值?

时间:2023-01-22 15:46:41

A pretty handy feature of Swift functions is that function parameters can have default values:

Swift函数的一个非常方便的特性是,函数参数可以具有默认值:

func someFunction(parameterWithDefault: Int = 42) {
    //if no arguments are passed to the function call,
    //value of parameterWithDefault is 42
}

If a parameter is a closure, is there a way to make it have a default value? See the example below:

如果参数是闭包,是否有方法使其具有默认值?看下面的例子:

func sendBody(
    body: NSData? = nil,
    success: (data: NSData) -> Void,
    failure: (data: NSData?) -> Void) {
}

Is there a way to not force the developer to pass a value for success or failure when calling sendBody?

是否有一种方法可以在调用sendBody时不强制开发人员传递成功或失败的值?

3 个解决方案

#1


26  

Yes, functions are just values you so you can supply them as defaults:

是的,函数只是你的值,所以你可以提供它们作为默认值:

// just to show you can do it with inline closures or regular functions
func doNothing<T>(t: T) -> Void { }

func sendBody(
    body: NSData? = nil,
    success: (data: NSData) -> Void = { _ in return },
    failure: (data: NSData?) -> Void = doNothing
)
{  }

Alternatively, you could make them optional, that way you can detect if the caller passed one:

或者,你也可以将它们设置为可选的,这样你就可以检测到呼叫者是否通过了:

func sendBody(
    body: NSData? = nil,
    success: ((NSData) -> Void)? = nil,
    failure: ((NSData?) -> Void)? = nil
    )
{ success?(NSData()) }

sendBody(success: { _ in print("ah, yeah!") })

Also worth noting if you’re doing this: if the caller uses the trailing closure syntax, this will be the last closure in the argument list. So you want the last one to be the one the user is most likely to want to supply, which is probably the success closure:

同样值得注意的是,如果调用者使用尾闭包语法,这将是参数列表中的最后一个闭包。所以你希望最后一个是用户最有可能提供的,这可能是成功的结尾:

func sendBody(
    body: NSData? = nil,
    success: ((NSData) -> Void)? = nil,
    failure: ((NSData?) -> Void)? = nil
    )
{
    if success != nil { print("passed a success closure") }
    if failure != nil { print("passed a failure closure") }
}

// this prints "passed a failure closure"
sendBody { data in
    print("which closure is this?")
}

Other than this, the order in the function declaration doesn’t matter to the caller – defaulted arguments can be supplied in any order.

除此之外,函数声明中的顺序对调用者不重要——默认参数可以按任何顺序提供。

#2


5  

You could do something like this,

你可以这样做,

let defaultSuccess: NSData -> Void = {
    (data: NSData) in

}

let defaultFailure: NSData? -> Void = {
    (data: NSData?) in
}

func sendBody( body: NSData? = nil, success: (data: NSData) -> Void = defaultSuccess, failure: (data: NSData?) -> Void = defaultFailure) {
}

Then, you may be able to call either one of these methods. Notice sendBody which is called with default parameters.

然后,您可以调用其中任何一个方法。请注意使用默认参数调用的sendBody。

sendBody()
sendBody(body: , success: , failure: )

You can also call with all the variants like passing just one of the argument in the above method, for that you have to call it with named parameter.

您还可以使用所有变体调用,比如在上面的方法中只传递一个参数,因为您必须使用命名参数调用它。

sendBody()
sendBody(body:)

sendBody(failure: )
sendBody(success:)

sendBody(body: , success: , failure: )

#3


1  

My preferred way to specify public facing closures - in particular completion closures which you might want to store somewhere for later - is to define a typealias for them, like this:

我指定面向公共的闭包的首选方法是,为它们定义一个类型别名,如下所示:

public typealias FooCompletion = (String) -> Void

Then in the public facing function you can easily make it optional like this:

在公众面前,你可以很容易地让它变成可选的:

var onCompletion: FooCompletion? = nil

public func foo(completion: FooCompletion? = nil) {
    // Store completion for later
    onCompletion = completion
}

The completion parameter is optional, so it's allowed to be nil, and the default value is nil, meaning the caller doesn't have to specify it. Also, because you use the type in more than one place, if you need to change its definition during development there's only one place to do so. It's easy to call too:

补全参数是可选的,所以允许为nil,默认值为nil,这意味着调用者不必指定它。而且,由于您在多个地方使用该类型,如果在开发期间需要更改其定义,那么只有一个地方可以这样做。打电话也很容易:

private func someBackgroundThing() {
    var completionString = "done"
    ...
    onCompletion?(completionString)
}

#1


26  

Yes, functions are just values you so you can supply them as defaults:

是的,函数只是你的值,所以你可以提供它们作为默认值:

// just to show you can do it with inline closures or regular functions
func doNothing<T>(t: T) -> Void { }

func sendBody(
    body: NSData? = nil,
    success: (data: NSData) -> Void = { _ in return },
    failure: (data: NSData?) -> Void = doNothing
)
{  }

Alternatively, you could make them optional, that way you can detect if the caller passed one:

或者,你也可以将它们设置为可选的,这样你就可以检测到呼叫者是否通过了:

func sendBody(
    body: NSData? = nil,
    success: ((NSData) -> Void)? = nil,
    failure: ((NSData?) -> Void)? = nil
    )
{ success?(NSData()) }

sendBody(success: { _ in print("ah, yeah!") })

Also worth noting if you’re doing this: if the caller uses the trailing closure syntax, this will be the last closure in the argument list. So you want the last one to be the one the user is most likely to want to supply, which is probably the success closure:

同样值得注意的是,如果调用者使用尾闭包语法,这将是参数列表中的最后一个闭包。所以你希望最后一个是用户最有可能提供的,这可能是成功的结尾:

func sendBody(
    body: NSData? = nil,
    success: ((NSData) -> Void)? = nil,
    failure: ((NSData?) -> Void)? = nil
    )
{
    if success != nil { print("passed a success closure") }
    if failure != nil { print("passed a failure closure") }
}

// this prints "passed a failure closure"
sendBody { data in
    print("which closure is this?")
}

Other than this, the order in the function declaration doesn’t matter to the caller – defaulted arguments can be supplied in any order.

除此之外,函数声明中的顺序对调用者不重要——默认参数可以按任何顺序提供。

#2


5  

You could do something like this,

你可以这样做,

let defaultSuccess: NSData -> Void = {
    (data: NSData) in

}

let defaultFailure: NSData? -> Void = {
    (data: NSData?) in
}

func sendBody( body: NSData? = nil, success: (data: NSData) -> Void = defaultSuccess, failure: (data: NSData?) -> Void = defaultFailure) {
}

Then, you may be able to call either one of these methods. Notice sendBody which is called with default parameters.

然后,您可以调用其中任何一个方法。请注意使用默认参数调用的sendBody。

sendBody()
sendBody(body: , success: , failure: )

You can also call with all the variants like passing just one of the argument in the above method, for that you have to call it with named parameter.

您还可以使用所有变体调用,比如在上面的方法中只传递一个参数,因为您必须使用命名参数调用它。

sendBody()
sendBody(body:)

sendBody(failure: )
sendBody(success:)

sendBody(body: , success: , failure: )

#3


1  

My preferred way to specify public facing closures - in particular completion closures which you might want to store somewhere for later - is to define a typealias for them, like this:

我指定面向公共的闭包的首选方法是,为它们定义一个类型别名,如下所示:

public typealias FooCompletion = (String) -> Void

Then in the public facing function you can easily make it optional like this:

在公众面前,你可以很容易地让它变成可选的:

var onCompletion: FooCompletion? = nil

public func foo(completion: FooCompletion? = nil) {
    // Store completion for later
    onCompletion = completion
}

The completion parameter is optional, so it's allowed to be nil, and the default value is nil, meaning the caller doesn't have to specify it. Also, because you use the type in more than one place, if you need to change its definition during development there's only one place to do so. It's easy to call too:

补全参数是可选的,所以允许为nil,默认值为nil,这意味着调用者不必指定它。而且,由于您在多个地方使用该类型,如果在开发期间需要更改其定义,那么只有一个地方可以这样做。打电话也很容易:

private func someBackgroundThing() {
    var completionString = "done"
    ...
    onCompletion?(completionString)
}