从 beta 8.3 开始,zillions 警告“字符串插值会为可选值生成调试描述;您是要明确说明吗?”出现在我的代码中。
例如,在以下情况下会弹出警告,其中 options 可能导致 nil:
let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"
正如之前设计的那样,我(和编译器)可以将可选项插入为“nil”。但是编译器改变了主意。
编译器建议添加一个 String 构造函数,其描述如下:
let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"
显然,结果是明确的,但在我看来也非常繁琐。有更好的选择吗?我必须修复所有这些警告还是更好地等待下一个测试版?
https://i.stack.imgur.com/llT41.png
Swift 3
破坏了我自己的 log
,而我只是使用 print
而犯了一个错误。应该始终创建自己的包装器,否则您会被这种“新功能”搞砸。
这是在 this pull request 中进行的更改,因为将 Optional(...)
插入到结果字符串中通常是不可取的,并且可能特别令人惊讶 in cases with implicitly unwrapped optionals。您可以在邮件列表 here 上查看有关此更改的完整讨论。
正如在拉取请求讨论中所提到的(尽管不幸不是 Xcode)——一种比使用 String(describing:)
更好的方式来消除警告是向您要插入的任何类型的可选类型添加强制转换,例如:
var i: Int? = 5
var d: Double? = nil
print("description of i: \(i as Int?)") // description of i: Optional(5)
print("description of d: \(d as Double?)") // description of d: nil
这也可以推广到 as Optional
:
print("description of i: \(i as Optional)") // description of i: Optional(5)
print("description of d: \(d as Optional)") // description of d: nil
在 Swift 5 中,使用 SE-0228 引入的新字符串插值系统,另一种选择是为 DefaultStringInterpolation
添加自定义 appendInterpolation
重载:
extension DefaultStringInterpolation {
mutating func appendInterpolation<T>(optional: T?) {
appendInterpolation(String(describing: optional))
}
}
var i: Int? = 5
var d: Double? = nil
print("description of i: \(optional: i)") // description of i: Optional(5)
print("description of d: \(optional: d)") // description of d: nil
而且,如果需要,您甚至可以删除参数标签以完全禁用模块内的警告(或者如果您将其标记为 fileprivate
,则在特定文件内):
extension DefaultStringInterpolation {
mutating func appendInterpolation<T>(_ optional: T?) {
appendInterpolation(String(describing: optional))
}
}
var i: Int? = 5
var d: Double? = nil
print("description of i: \(i)") // description of i: Optional(5)
print("description of d: \(d)") // description of d: nil
虽然我个人更愿意保留参数标签。
处理这个问题的两种更简单的方法。
选项1:
第一种是通过“强制展开”您想要使用 bang (!) 返回的值
var someValue: Int? = 5
print(someValue!)
输出:
5
选项 2:
另一种方法,可能是更好的方法 - 是“安全地解开”你想要返回的值。
var someValue: Int? = 5
if let newValue = someValue {
print(newValue)
}
输出:
5
建议选择选项 2。
提示:尽可能避免强制展开 (!),因为我们不确定是否总是有要展开的值。
似乎使用 String(describing:optional) 是最简单的。
默认值 ??对非字符串没有意义,例如 Int。如果 Int 为 nil,那么您希望日志显示“nil”而不是默认为另一个 Int,例如 0。
一些要测试的操场代码:
var optionalString : String? = nil
var optionalInt : Int? = nil
var description_ = ""
description_ = description_ + "optionalString: \(String(describing: optionalString))\r"
description_ = description_ + " optionalInt: \(String(describing: optionalInt))\r"
print(description_)
输出
optionalString: nil
optionalInt: nil
在更新到 Xcode 8.3 并收到大量警告消息后,我想出了以下更类似于原始输出行为的内容,易于添加,减少了在代码和输出中使用“String(describing:)”的冗长性.
基本上,添加一个可选扩展,它提供一个描述可选内容的字符串,或者如果未设置,则简单地为“nil”。另外,如果 optional 中的东西是一个 String,把它放在引号里。
extension Optional {
var orNil : String {
if self == nil {
return "nil"
}
if "\(Wrapped.self)" == "String" {
return "\"\(self!)\""
}
return "\(self!)"
}
}
并在操场上使用:
var s : String?
var i : Int?
var d : Double?
var mixed = "s = \(s.orNil) i = \(i.orNil) d = \(d.orNil)" // "s = nil i = nil d = nil"
d = 3
i = 5
s = ""
mixed = "s = \(s.orNil) i = \(i.orNil) d = \(d.orNil)" // "s = "" i = 5 d = 3.0"
s = "Test"
d = nil
mixed = "s = \(s.orNil) i = \(i.orNil) d = \(d.orNil)" // "s = "Test" i = 5 d = nil"
感谢以下链接的帮助:
check-if-variable-is-an-optional-and-what-type-it-wraps
a?.b?.c.orNil
。
See Ole Begeman's fix for this。我喜欢它。它创建一个 ???
运算符,然后您可以像这样使用它:
var someValue: Int? = 5
print("The value is \(someValue ??? "unknown")")
// → "The value is 5"
someValue = nil
print("The value is \(someValue ??? "unknown")")
// → "The value is unknown"
双击包含此警告的行上显示的黄色三角形。这将显示带有两个解决方案的 FixIt。
https://i.stack.imgur.com/kyzTQ.png
使用 String(describing:) 来消除这个警告:使用它会变成 String(describing:
斯威夫特 5
我的解决方案是制作一个将 Optional
对象解包到 Any
的 extension
。
当您记录对象或将其打印出来时,您可以看到实际的 object
或 <nil>⭕️
(文本和视觉字符的组合)。查看它很有用,尤其是在控制台日志中。
extension Optional {
var logable: Any {
switch self {
case .none:
return "<nil>|⭕️"
case let .some(value):
return value
}
}
}
// sample
var x: Int?
print("Logging optional without warning: \(x.logable)")
// → Logging optional without warning: <nil>|⭕️
创建一个插值方法,该方法接受带有未命名参数的可选泛型类型。你所有烦人的警告都会神奇地消失。
extension DefaultStringInterpolation {
mutating func appendInterpolation<T>(_ optional: T?) {
appendInterpolation(String(describing: optional))
}
}
?? "nil"
使警告静音,这似乎有点受欢迎,因此可能会在不久的将来出现在另一个提案中。我确实同意这种解决方法不太理想——就个人而言,我认为将Optional(...)
插入到字符串中作为一个强选项是相当明显的——只有 IUO 的情况才需要这个警告 IMO。但是 Swift 一直在不断发展,所以这一切都可能在以后发生变化。但就目前而言,这就是我们所拥有的。guard result == nil else { print("result was \(result as Optional)") return }
if let
?即if let result = result { print("result was \(result)"); return }
。并非所有的早期回报都需要与警卫一起完成。