为啥速记参数名称在这个 Swift 闭包中不起作用?

Posted

技术标签:

【中文标题】为啥速记参数名称在这个 Swift 闭包中不起作用?【英文标题】:Why don't shorthand argument names work in this Swift closure?为什么速记参数名称在这个 Swift 闭包中不起作用? 【发布时间】:2015-10-27 03:51:03 【问题描述】:

这是一个 Swift 函数,它接受两个整数和一个三参数函数,并调用传入的函数。

func p(x:Int, _ y:Int, _ f: (Int, Int, Int) -> ()) 
    f(x, y, 0)

我可以使用尾随闭包语法和速记参数名称来调用它,没问题:

> p(1, 2) print($0 + $1 + $2)

3

按预期工作。但是在Foundation库中,有一个字符串方法叫enumerateSubstringsInRange,定义如下:

func enumerateSubstringsInRange(
      _ range: Range<Index>, 
      options opts: NSStringEnumerationOptions, 
      _ body: (substring: String?, 
               substringRange: Range<Index>, 
               enclosingRange: Range<Index>, 
               inout Bool) -> ())

好的,这很简单:该函数接受三个参数,最后一个是四参数函数。就像我的第一个例子一样!或者我是这么想的......

我可以将此函数与尾随闭包语法一起使用,但我不能使用速记参数名称!我不知道为什么。这是我尝试过的:

let s = "a b c"
"a b c".enumerateSubstringsInRange(s.characters.indices, options: .ByWords) (w,_,_,_) in print(w!) 

a
b
c

一切都好;我只是想打印出匹配的单词,一次一个。当我将闭包指定为 `(w,,,_) in print(w!)` 时,这很有效。但是,当我尝试使用速记参数语法编写闭包时,灾难:

> "a b c".enumerateSubstringsInRange(s.characters.indices, options: .ByWords) print($0!)
repl.swift:9:86: error: cannot force unwrap value of non-optional type   '(substring: String?, substringRange: Range<Index>, enclosingRange: Range<Index>, inout Bool)' (aka '(substring: Optional<String>, substringRange: Range<String.CharacterView.Index>, enclosingRange: Range<String.CharacterView.Index>, inout Bool)')

那我做错了什么?!错误消息似乎表明闭包参数$0args 的整个元组。确实,当我尝试这样做时,似乎确实如此!

>"a b c".enumerateSubstringsInRange(s.characters.indices, options: .ByWords) print($0.0!)

a 
b
c

所以我非常困惑。为什么在第一种情况下(我的函数p,参数被理解为$0$1 等,但在第二种情况下,所有参数都汇总成一个元组?或者是吗?FWIW ,我找到了 enumerateSubstringsInRange here 的签名。

【问题讨论】:

【参考方案1】:

这取决于参数的数量。

例如,

func test( closure: (Int,Int,Int) -> Void )
    // do something

要使test 按预期工作,您必须指定$2(第三个参数)。编译器将推断元组内部的值,否则它将推断元组本身。

如果你没有指定$number 匹配的参数数量。比如只指定$1,会编译出错。

// work as expected ( infer to int )
test
    print($2)

test
    print($1+$2)

test
    print($0+$1+$2)


// not work ( infer to tuple )
test
    print($0)


// not work ( cannot infer and compile error )
test
    print($1)

有一个问题与这个问题有关。 Why is the shorthand argument name $0 returning a tuple of all parameters?

【讨论】:

以上是关于为啥速记参数名称在这个 Swift 闭包中不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 private(set) 在 Swift 中不起作用?

为啥两个表格视图单元格中的两个集合视图在 Swift 4 中不起作用?

为啥类型转换在 Swift 2.0 中不起作用?

速记中的 CSS3 动画播放状态在 IE 和 Safari 中不起作用

Swift UrlSession 在 UrlSession 中不起作用

为啥模板参数推导在 C++ 中不起作用?