Swift iOS 12 SDK通用函数返回可选的.some(nil)
使用Xcode 10,但没有迁移到Swift 4.2,因此我的项目仍然使用Swift 4.1运行 假设我在Swift iOS 12 SDK通用函数返回可选的.some(nil),swift,generics,Swift,Generics,使用Xcode 10,但没有迁移到Swift 4.2,因此我的项目仍然使用Swift 4.1运行 假设我在字典上有以下扩展名: extension Dictionary where Key: ExpressibleByStringLiteral { func find<T>(key: Key) -> T? { return self[key] as? T } } 当我希望从我的find函数返回Any类型时,问题就出现了,比如: let bar
字典上有以下扩展名:
extension Dictionary where Key: ExpressibleByStringLiteral {
func find<T>(key: Key) -> T? {
return self[key] as? T
}
}
当我希望从我的find
函数返回Any
类型时,问题就出现了,比如:
let bar: Any? = dict.find(key: "bar")
在Xcode 10之前,如果在hashmap中找不到键,此函数用于返回给我简单明了的nil
但是,在Xcode 10之后,它返回可选的.some(nil)
我理解,任何类型都可以按以下方式初始化:
let foo: Any = Optional<String>.none
让foo:Any=Optional.none
我想在我的情况下也会发生类似的事情。是否有人有想法,如何解决它,并且仍然从find
函数返回nil
?这是由于一个有意的更改(),编译器现在更加保守,将强制转换为通用占位符类型的可选值展开。现在,您得到的结果与您在非泛型上下文中得到的结果更加一致(有关进一步讨论,请参阅)
例如:
// note the constraint `where Key : ExpressibleByStringLiteral` is needlessly restrictive.
extension Dictionary where Key : ExpressibleByStringLiteral {
func find<T>(key: Key) -> T? {
return self[key] as? T
}
}
let dict: [String: Any] = ["foo": "bar"]
let genericBar: Any? = dict.find(key: "bar")
print(genericBar as Any) // in Swift 4.1: nil, in Swift 4.2: Optional(nil)
// `T` in the above example is inferred to be `Any`.
// Let's therefore substitute `as? T` with `as? Any`.
let nonGenericBar = dict["bar"] as? Any
print(nonGenericBar as Any) // in both versions: Optional(nil)
或在强制转换前打开值,例如使用防护装置:
extension Dictionary {
func find<T>(key: Key) -> T? {
guard let value = self[key] else { return nil }
return value as? T
}
}
话虽如此,我经常发现[String:Any]
的用法是一种代码味道,强烈地表明应该使用更强的类型。除非键可以是任意字符串(而不是一组固定的静态已知键),并且值可以是特定键的任何类型,否则几乎可以肯定有一种更好的类型可以用于数据建模。在错误得到修复之前,您似乎一直在使用显式、具体的类型,与任何?
:)@Cristik不同的是,行为改变本身并不是一个bug,新的行为将继续存在(希望如此)。错误在于,新行为没有正确地限制在-swift版本5
以最好地保持兼容性。也许我遗漏了一些东西,但为什么let bar:String?=dict.find(键:“bar”)
不会以两级选项结束(它打印nil
,而不是可选(nil)
?它是相同的代码,与应用于一个已经可选的值的相同。它是相同的代码,只是使用字符串而不是任何,但行为不同。@Cristik在这种情况下,T
被推断为String
,所以您正在执行dict[“bar”]as?String
。由于您要转换为非可选的具体类型,Swift将打开从下标返回的值,以查看它是否为字符串。如果是,则返回可选(值)
作为强制转换的成功结果。如果不是,则作为失败的强制转换结果,它将返回nil
。与as-Any
的区别在于Swift不会打开该值。为什么?因为任何东西都可以键入Any
,包括Optional
。因此Swift会很高兴地在Any
中加上一个可选框然后在另一个Optional
中包装它作为演员的成功结果。一般来说,最好避免将Optional
和Any
混合在一起,因为这种行为很快就会变得非常混乱–一个Optional
可以被删除为Any
,而一个Any
可以被提升为Optional
。谢谢,Any
都可以保存Optional,这就是编译器不将其展开的原因,因为它不知道调用者是否需要它。
extension Dictionary {
func find<T>(key: Key) -> T? {
return (self[key] as? T?) ?? nil
}
}
extension Dictionary {
func find<T>(key: Key) -> T? {
guard let value = self[key] else { return nil }
return value as? T
}
}
extension Dictionary {
func find<T>(key: Key) -> T? {
return self[key].flatMap { $0 as? T }
}
}