Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift iOS 12 SDK通用函数返回可选的.some(nil)_Swift_Generics - Fatal编程技术网

Swift iOS 12 SDK通用函数返回可选的.some(nil)

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

使用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: 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 }
  }
}