为什么 Swift nil-coalescing 三元运算符 return 不展开类型?
Why doesn't Swift nil-coalescing ternary operator return unwrapped type?
我读到三元运算符 ??
解包一个可选的,如果它不是零,但如果我这样做:
var type: String?
type = "milk"
let certainType = type ?? "melon"
那么 certainType 仍然是 String?
,如果我这样做
println("it's a \(certainType)")
它将打印:
it's a Optional("milk")
想法?
更新:
抱歉造成混淆 - 我的意思是 var type: String?
我知道它应该打印 "it's a milk",但我在控制台中看到的是 "it's a Optional("milk")" - 其他人遇到过同样的问题吗?会不会是字符串插值引起的?
@Antonio 询问,这里有更多上下文和真实代码以及日志记录快照 - 类型来自 Note,它是一个 NSManagedObject class 用于处理 xcdatamodel
class Note: NSManagedObject {
@NSManaged var type: String?
}
并且我在某个时候将类型设置为 'todo',然后使用以下代码将它们打印出来:
println("type class:\(_stdlib_getDemangledTypeName(note.type))")
let type1 = note.type ?? "note"
println("type1:\(type1)")
let type2: String = note.type ?? "note"
println("type2:\(type2)")
并且输出:
type class:Swift.Optional
type1:Optional("todo")
type2:todo
如您所见,如果我没有明确地将 type1 的类型标记为 String,它将打印不需要的结果 Optional("todo") - 我在字符串插值中使用该类型来构造路径,所以这很重要
这是(我认为)设计使然。如果你这样做:
let type = "mil"
println("it's a \(type)")
如果我没记错的话,这将打印 it's a "milk"
,这在调试时比 it's a String
更有用。请注意,\(...)
类似于 Objective-C 中的 %@
:类 可以覆盖其字符串表示形式。
此外,正如安东尼奥已经指出的那样:
- 您不能更改不可变变量(即
let
)。
- 可选的 let 变量因此是无用的(即不要做
let type: String? = "milk"
因为它显然永远不会为 nil)。
I read that the ternary operator ?? unwraps an optional if it is not nil, but...
它确实打开了它。
let type: String?
type = "milk"
let certainType = type ?? "melon"
您的代码无法编译,但如果您将 let 更改为 var,它将起作用并且某些类型将为 String 类型。
var type: String?
type = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)") // prints "it's a milk"
这被称为 Nil Coalescing Operator。
如果你有一个可选的 a
,如果 a
不是 nil
和 b
,a ?? b
的结果将是 a!
如果是。这个表达式是shorthand:
a != nil ? a! : b
因此,您正确使用了运算符,但您必须在声明它的同一行上初始化一个常量:
let type: String? = "milk"
但是,我假设您不希望它在这种情况下成为常量(因为您正在检查它是什么),所以如果您使用 var
来声明它,您的现有代码应该可以工作。
我无法证明我要说的话,所以非常感谢任何反馈。
OP 断言代码与此类似:
var type: String? = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)")
打印出意外的字符串:
"it's a Optional("milk")"
而应该是:
"it's a milk"
事实证明,当变量实际上是具有 @NSManaged
属性的 属性 时,就会发生这种情况。
我怀疑类型推断有问题。 OP 指出:
let certainType = type ?? "melon"
打印错误结果,而:
let certainType: String = type ?? "melon"
打印正确的。
因此 出于某种原因,nil 合并运算符在没有明确指示变量类型的情况下返回一个可选的。
如果我将 type
变量的类型更改为 AnyObject
或 AnyObject?
,它实际上会打印 unexpected 结果:
var type: AnyObject = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)")
"it's a Optional(milk)"
我的猜测是:因为使用了@NSManaged
属性,属性在使用时被推断出错误的类型(AnyObject?
),除非正确的明确指出类型.
至于为什么会这样,不知道(除了认为这是一个错误)
随意对这个答案投赞成票或反对票,最重要的是不要将其视为解决方案 - 不过我会很感激反馈,因为我很想知道发生了什么以及它是否真的是错误或没有。
这就是你想要的
let certainType = type! ?? "melon"
注意我展开类型。它适用于您:
let type2: String = note.type ?? "note"
因为您实际上是在转换为 String 时解包。
我遇到了类似的问题。
我有一个 [String : AnyObject]
类型的字典,但我找到的条目结果是一个 String
值。担心它可能并不总是存在。我正在使用以下代码检索它:
let message = dictionary["message"] ?? "No message"
但是,当条目存在时,仍会给出字符串:
Optional(the actual message)
即变量message
的类型为String?
。
我改成了:
let message = (dictionary["message"] as? String) ?? "No message"
...现在检索到的值是一个未包装的非可选字符串。
我的问题是 @NSManaged
类型 NSNumber?
的属性,我试图将其包装在字符串中。
let time = "\(nsManagedObject.optionalNsNumber ?? "") months"
/// result "Optional(<random number>) months"
此问题的解决方案是将 NSNumber
转换为 stringValue
。下面是按预期工作的代码。
let time = "\(nsManagedObject.optionalNsNumber.stringValue ?? "") months"
/// result "<random number> months"
Swift 如果值被包裹在字符串中,编译器将不会发现问题。如果您尝试使用 nil coalescing
运算符,然后将结果添加到字符串中,它将指向手头的错误,Can't add NSObject and String
.
将 @NSManaged
属性包装成字符串时要小心。
我找到了一个方法试试看。
infix operator ???
/// use this custom operator to overcome issue related to '??' which always needs assignment to remove Optional
///
/// - parameter lhs: left hand side variable
/// - parameter rhs: right hand side variable
///
/// - returns: it will return unwrapped value of one of the variable which has not nil value
func ???(lhs: Any?, rhs: Any?) -> Any {
let temp : Any = lhs ?? rhs
return temp
}
我读到三元运算符 ??
解包一个可选的,如果它不是零,但如果我这样做:
var type: String?
type = "milk"
let certainType = type ?? "melon"
那么 certainType 仍然是 String?
,如果我这样做
println("it's a \(certainType)")
它将打印:
it's a Optional("milk")
想法?
更新:
抱歉造成混淆 - 我的意思是 var type: String?
我知道它应该打印 "it's a milk",但我在控制台中看到的是 "it's a Optional("milk")" - 其他人遇到过同样的问题吗?会不会是字符串插值引起的?
@Antonio 询问,这里有更多上下文和真实代码以及日志记录快照 - 类型来自 Note,它是一个 NSManagedObject class 用于处理 xcdatamodel
class Note: NSManagedObject {
@NSManaged var type: String?
}
并且我在某个时候将类型设置为 'todo',然后使用以下代码将它们打印出来:
println("type class:\(_stdlib_getDemangledTypeName(note.type))")
let type1 = note.type ?? "note"
println("type1:\(type1)")
let type2: String = note.type ?? "note"
println("type2:\(type2)")
并且输出:
type class:Swift.Optional
type1:Optional("todo")
type2:todo
如您所见,如果我没有明确地将 type1 的类型标记为 String,它将打印不需要的结果 Optional("todo") - 我在字符串插值中使用该类型来构造路径,所以这很重要
这是(我认为)设计使然。如果你这样做:
let type = "mil"
println("it's a \(type)")
如果我没记错的话,这将打印 it's a "milk"
,这在调试时比 it's a String
更有用。请注意,\(...)
类似于 Objective-C 中的 %@
:类 可以覆盖其字符串表示形式。
此外,正如安东尼奥已经指出的那样:
- 您不能更改不可变变量(即
let
)。 - 可选的 let 变量因此是无用的(即不要做
let type: String? = "milk"
因为它显然永远不会为 nil)。
I read that the ternary operator ?? unwraps an optional if it is not nil, but...
它确实打开了它。
let type: String? type = "milk" let certainType = type ?? "melon"
您的代码无法编译,但如果您将 let 更改为 var,它将起作用并且某些类型将为 String 类型。
var type: String?
type = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)") // prints "it's a milk"
这被称为 Nil Coalescing Operator。
如果你有一个可选的 a
,如果 a
不是 nil
和 b
,a ?? b
的结果将是 a!
如果是。这个表达式是shorthand:
a != nil ? a! : b
因此,您正确使用了运算符,但您必须在声明它的同一行上初始化一个常量:
let type: String? = "milk"
但是,我假设您不希望它在这种情况下成为常量(因为您正在检查它是什么),所以如果您使用 var
来声明它,您的现有代码应该可以工作。
我无法证明我要说的话,所以非常感谢任何反馈。
OP 断言代码与此类似:
var type: String? = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)")
打印出意外的字符串:
"it's a Optional("milk")"
而应该是:
"it's a milk"
事实证明,当变量实际上是具有 @NSManaged
属性的 属性 时,就会发生这种情况。
我怀疑类型推断有问题。 OP 指出:
let certainType = type ?? "melon"
打印错误结果,而:
let certainType: String = type ?? "melon"
打印正确的。
因此 出于某种原因,nil 合并运算符在没有明确指示变量类型的情况下返回一个可选的。
如果我将 type
变量的类型更改为 AnyObject
或 AnyObject?
,它实际上会打印 unexpected 结果:
var type: AnyObject = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)")
"it's a Optional(milk)"
我的猜测是:因为使用了@NSManaged
属性,属性在使用时被推断出错误的类型(AnyObject?
),除非正确的明确指出类型.
至于为什么会这样,不知道(除了认为这是一个错误)
随意对这个答案投赞成票或反对票,最重要的是不要将其视为解决方案 - 不过我会很感激反馈,因为我很想知道发生了什么以及它是否真的是错误或没有。
这就是你想要的
let certainType = type! ?? "melon"
注意我展开类型。它适用于您:
let type2: String = note.type ?? "note"
因为您实际上是在转换为 String 时解包。
我遇到了类似的问题。
我有一个 [String : AnyObject]
类型的字典,但我找到的条目结果是一个 String
值。担心它可能并不总是存在。我正在使用以下代码检索它:
let message = dictionary["message"] ?? "No message"
但是,当条目存在时,仍会给出字符串:
Optional(the actual message)
即变量message
的类型为String?
。
我改成了:
let message = (dictionary["message"] as? String) ?? "No message"
...现在检索到的值是一个未包装的非可选字符串。
我的问题是 @NSManaged
类型 NSNumber?
的属性,我试图将其包装在字符串中。
let time = "\(nsManagedObject.optionalNsNumber ?? "") months"
/// result "Optional(<random number>) months"
此问题的解决方案是将 NSNumber
转换为 stringValue
。下面是按预期工作的代码。
let time = "\(nsManagedObject.optionalNsNumber.stringValue ?? "") months"
/// result "<random number> months"
Swift 如果值被包裹在字符串中,编译器将不会发现问题。如果您尝试使用 nil coalescing
运算符,然后将结果添加到字符串中,它将指向手头的错误,Can't add NSObject and String
.
将 @NSManaged
属性包装成字符串时要小心。
我找到了一个方法试试看。
infix operator ???
/// use this custom operator to overcome issue related to '??' which always needs assignment to remove Optional
///
/// - parameter lhs: left hand side variable
/// - parameter rhs: right hand side variable
///
/// - returns: it will return unwrapped value of one of the variable which has not nil value
func ???(lhs: Any?, rhs: Any?) -> Any {
let temp : Any = lhs ?? rhs
return temp
}