为什么Swift的nil-coalescing三元运算符不返回未 Package 的类型?

bvk5enib  于 2022-10-31  发布在  Swift
关注(0)|答案(8)|浏览(134)

我读到三元运算符??如果不是nil,就打开一个可选的,但是如果我这样做:

var type: String?
type = "milk"
let certainType = type ?? "melon"

那么certainType仍然是String?

println("it's a \(certainType)")

它将打印:

it's a Optional("milk")

有什么想法?
更新:
很抱歉造成混淆-我指的是var类型:绳子?
我知道它应该打印“it 's a milk”,但我在控制台中看到的是“it' s a Optional(“milk”)”--其他人也遇到过同样的问题吗?这会不会是字符串插值引起的?
由@Antonio询问,这里有更多的上下文和真实的代码以及日志快照--类型来自Note,这是一个用于处理xcdatamodel的NSManagedObject类

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

正如您所看到的,如果我不显式地将type 1的类型标记为String,它将输出不希望的结果可选(“todo”)-我在字符串插值中使用该类型来构造路径,因此它很重要

qvk1mo1f

qvk1mo1f1#

OPAssert代码类似于:

var type: String? = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)")

打印意外的字符串:
它是可选的(“milk”)
而它应该是:
“这是牛奶”
事实证明,当变量实际上是一个具有@NSManaged属性的属性时,就会发生这种情况。
我怀疑在类型推断中有一个bug。OP声明:

let certainType = type ?? "melon"

打印错误的结果,而:

let certainType: String = type ?? "melon"

打印正确的一个。
因此,* 由于某种原因,在没有显式指示变量类型的情况下,nil合并运算符返回一个可选的 *。

如果我将type变量的类型更改为AnyObjectAnyObject?,它实际上会输出 * 意外 * 结果

var type: AnyObject = "milk"
let certainType = type ?? "melon"
println("it's a \(certainType)")

“它是可选的(牛奶)”
我的猜测是:* 因为使用了@NSManaged属性,所以除非明确指示正确的型别,否则在使用时会以错误的型别(AnyObject?)来推断属性(Property)*。
至于为什么会发生这种情况,不知道(除了认为这是一个错误)

uwopmtnx

uwopmtnx2#

这是(我认为)设计好的。如果你这样做:

let type = "mil"
println("it's a \(type)")

如果我没弄错的话,这将打印it's a "milk",它在调试时比it's a String有用得多。注意,\(...)类似于Objective-C中的%@:类可以重写它们的字符串表示形式。
此外,正如安东尼奥已经指出的:
1.不能更改不可变变量(即let)。
1.因此,可选的let变量是无用的(也就是说,不要执行let type: String? = "milk",因为它显然永远不会为nil)。

jyztefdp

jyztefdp3#

我读到三元运算符??如果不是nil,就打开可选的,但是...
它会打开它。
字母类型:字符串?type =“milk”字母类型:
您的代码将无法编译,但如果您将let更改为var,它将工作,并且certainType将为String类型。

var type: String?
type = "milk"
let certainType = type ?? "melon"

println("it's a \(certainType)") // prints "it's a milk"
gg58donl

gg58donl4#

这就是所谓的零合并运算符。
如果您有一个Optional a,则当a不是nil时,a ?? b的结果将是a!,而当nilb时,a ?? b的结果将是b。它是以下表达式的简写:

a != nil ? a! : b

因此,您正确地使用了运算子,但必须在宣告常数的同一行上初始化常数:

let type: String? = "milk"

但是,我假设您不希望它在此上下文中成为常量(因为您要检查它是什么),因此如果使用var声明它,现有代码应该可以工作。

64jmpszr

64jmpszr5#

我也有类似的问题。
我有一个类型为[String : AnyObject]的字典,但是我查找的条目是一个String值。我担心它可能并不总是存在。我用下面的代码检索它:

let message = dictionary["message"] ?? "No message"

但是,当条目存在时,仍然会给予字符串:
可选(实际消息)
即变量message的类型为String?
我把它改成:

let message = (dictionary["message"] as? String) ?? "No message"

...现在检索到的值是一个未 Package 的非可选字符串。

gc0ot86w

gc0ot86w6#

这就是你想要的

let certainType = type! ?? "melon"

请注意,我打开了类型。它在以下情况下有效:

let type2: String = note.type ?? "note"

因为您实际上是在向String的转换中展开。

zc0qhyus

zc0qhyus7#

在我的例子中,问题是NSNumber?类型的@NSManaged属性,我试图将其 Package 在字符串中。
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属性 Package 到字符串中时要小心。

svgewumm

svgewumm8#

我找到一个办法试试看。

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

}

相关问题