相同的下标代码,当用两行单独的代码构建它时它工作正常,当用一行代码构建它时,我得到一个错误,为什么?



我添加了两张代码图片,解释了两种场景 在第一种情况下,下标的工作方式与它应该工作的方式完全相同,有两行代码

在 Secound 场景中,代码的计算结果应该与两行相同,但由于某种原因我收到错误

你能帮我弄清楚为什么吗?

工作图像:工作图像

错误图像:错误图像

完整代码:

class SomeClass {
var dic = Dictionary<String,(()->String) -> String>()
subscript(_ s:String) -> (()->String) -> String {
get{
return dic[s]!
}set{
dic[s] = newValue
}

}

}

func createClass(_ s:String) -> SomeClass {
func foo(_ str:()->String) ->String {
return str() + " AND " + "Two"
}
let sc = SomeClass()
sc["0"] = foo
return sc
}

// WORKING TWO LINES
let someClass  = createClass("someStr")["0"]
let str = someClass{"One"} // everything work fine, no errors // prints 'One AND Two'

// ERROR ONE LINE
let str  = createClass("someStr")["0"]{"One"}

// WHY?

你需要在createClass("someStr")["0"]两边加上括号,因为它在用下标评估createClass("someStr")之前试图评估["0"]{"One"}。即使进行此更改,也会收到编译错误,因为您声明了两次变量str

有时,有两个单独的陈述更容易(更不用说更清晰了(,而不是试图变得聪明。

var str = "Hello, playground"
class SomeClass {
var dic = Dictionary<String,(()->String) -> String>()
subscript(_ s:String) -> (()->String) -> String {
get{
return dic[s]!
}set{
dic[s] = newValue
}
}
}
func createClass(_ s:String) -> SomeClass {
func foo(_ str:()->String) ->String {
return str() + " AND " + "Two"
}
let sc = SomeClass()
sc["0"] = foo
return sc
}
str = (createClass("someStr")["0"]){"One"}
print(str) // One AND Two

您的示例:

let str = createClass("someStr")["0"]{"One"}

使用尾随闭包语法

随闭包语法的工作原理是将尾随闭包作为函数调用的附加参数包含在内。 下标数组实际上是底层的函数调用(对名为subscript的函数(,Swift 试图将该闭包作为第二个参数传递给下标调用,这就是错误所解释的:

不能使用类型为"(字符串,(( -> 字符串("的参数下标类型为"SomeClass"的值。

换句话说,不能将"0"和闭包{"One"}传递给下标函数。


至少有 3 种方法可以解决此问题,并且仍然将其放在一行上:

选项 1:使用显式调用来传递闭包,而不是使用尾随闭包语法

将闭包包装在()中以使调用显式

let str1 = createClass("someStr")["0"]({"One"})
print(str1)

选项 2:将createClass("someStr")["0"]括在括号中

这让 Swift 知道下标仅作为参数"0",并允许尾随闭包语法按预期工作:

let str2 = (createClass("someStr")["0"]){"One"}
print(str2)

选项 3:在尾随闭包语法之前向结果添加.self

这再次完成了下标调用并避免了混淆。

let str3 = createClass("someStr")["0"].self {"One"}
print(str3)

就个人而言,我会选择选项 1,因为尾随闭包语法是不必要的语法糖,显然在这里不起作用。


解决挑战

在评论中,我问:

我同意尾随闭包语法很可能

是他们可以修复的错误,但我不明白的是为什么你坚持在这里使用尾随闭包语法。将闭包包装在 (( 中以使调用显式,即使它只是为了解决 Swift 中的错误,这有什么令人反感的?

你回答说:

坚持的

原因是我试图解决一个挑战。 实际上,这个返回闭包的函数只是它的一面 它是这样的

func Challenge() {
// Do not edit below this line
XCTAssertEqual(foo("str1")["str2"]{ "654321" }, "123456")
}

我们已经确定尾随闭包语法将最终闭包与索引操作配对,因此诀窍是设计一个采用闭包及其索引操作的类:

class SomeClass {
subscript(_ s: String, closure: () -> String) -> String {
return String(closure().reversed())
}
}
func foo(_ str: String) -> SomeClass {
return SomeClass()
}
func Challenge() {
// Do not edit below this line
XCTAssertEqual(foo("str1")["str2"]{ "654321" }, "123456")
}

最新更新