为什么块外 swift 看不到分配给块中未初始化变量的值?

Why outside of block swift can't see value assigned to a uninitialized variable in the block?

在 Swift5 中声明 w/o 值的机制是什么?第一个赋值是否成为真正的声明?

而且,我们是否应该避免在 Swift 中声明没有价值?

var v:String;
if true {
    v = "Hello"
    print(v) // print "Hello" when without the print below
}
print(v) // variable 'v' used before being initialized
var v:String="";
if true {
    v = "Hello"
    print(v) // print "Hello"
}
print(v) // print "Hello"

所以这是因为 swift 编译您的代码并注意到您的值 var v:String; 在使用之前未声明,这使其成为 "optional" 值。即使你在 if 语句中分配它,如果你要摆脱 true 值,if 语句可能永远不会 运行 因此没有值会存储在 v 中,因此它会在 "assigned".

之前使用

所以回答你的问题,如果你希望你的值是一个可选的和可能的空值声明 v 如下 var v:String? 如果你希望它是一个 non-optional 值始终存储在 v 中,您应该将其声明为以下 var v = ""。 Swift 会将此声明解释为字符串。

要回答你的第二个问题,在 swift 中定义没有值是 100% 允许的,这实际上只取决于你想如何处理你的代码。我一直在我的代码中使用可选值,但我不一定喜欢可选值所以我通常喜欢声明我的值,例如 var v = "" 如果值为空我的 UI 或其他任何东西我正在操纵不会破裂。但是,如果我需要确保存在一个值,我必须将我的值设为可选,这样我就可以使用 if 语句来检查它是否是一个有效值。

我想说的更简短的版本是,您收到编译器警告是因为您将 v 声明为 non-optional 值而不是可选值。

好吧,这个消息不是很有帮助,这就是问题所在。这种模式(我称之为 computed initialization)是完全合法且有用的,而且——令人惊讶的是——你甚至可以使用 let 而不是 var。但是你必须在使用它之前通过所有可能的路径初始化未初始化的变量。所以你有:

var v:String
if true {
    v = "Hello"
}
print(v) // error

但是拿着我的啤酒看这个:

var v:String
if true {
    v = "Hello"
} else {
    v = "Goodbye"
}
print(v) // fine!

甚至:

let v:String
if true {
    v = "Hello"
} else {
    v = "Goodbye"
}
print(v) // fine!

太棒了,嗯?

现在,您可能会说:好的,但是 true 将永远为真,所以让我满足 "all paths" 规则是愚蠢的。太糟糕了!编译器无论如何都会坚持,然后让你稍后警告 else 不会被执行。但是一个警告让你编译;错误不会。事实是您的示例非常人为。但这是 real-life 的可能性:

let v:String
if self.someBoolProperty {
    v = "Hello"
} else {
    v = "Goodbye"
}
print(v) // fine!

不仅这种事情是合法的,而且在某些稍微棘手的情况下,它实际上是 Apple 推荐 的模式。例如,它用于 Apple 自己的 example code 展示如何使用 Swift 5 结果结构:

let result: Result<Int, EntropyError>
if count < AsyncRandomGenerator.entropyLimit {
    // Produce numbers until reaching the entropy limit.
    result = .success(Int.random(in: 1...100))
} else {
    // Supply a failure reason when the caller hits the limit.
    result = .failure(.entropyDepleted)
}