【发布时间】:2016-01-18 14:05:16
【问题描述】:
我们正在尝试确定这是 Swift 中的错误,还是我们滥用泛型、可选项、类型推断和/或 nil 合并运算符。
我们的框架包含一些用于将字典解析为模型的代码,我们遇到了一个带有默认值的可选属性的问题。
我们有一个协议SomeProtocol 和一个协议扩展中定义的两个通用函数:
mapped<T>(...) -> T?
mapped<T : SomeProtocol>(...) -> T?
我们的结构和类遵循此协议,然后在协议所需的 init 函数中解析它们的属性。
在init(...) 函数中,我们尝试像这样设置属性someNumber 的值:
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
字典当然包含键 someNumber 的实际值。但是,这将始终失败,并且永远不会从 mapped() 函数返回实际值。
注释掉第二个泛型函数或强制向下转换赋值的 rhs 值将解决此问题,但我们认为这应该按照当前编写的方式工作。
以下是演示问题的完整代码 sn-p,以及两个选项(临时)修复代码中标记为 OPTION 1 和 OPTION 2 的问题:
import Foundation
// Some protocol
protocol SomeProtocol {
init(dictionary: NSDictionary?)
}
extension SomeProtocol {
func mapped<T>(dictionary: NSDictionary?, key: String) -> T? {
guard let dictionary = dictionary else {
return nil
}
let source = dictionary[key]
switch source {
case is T:
return source as? T
default:
break
}
return nil
}
// ---
// OPTION 1: Commenting out this makes it work
// ---
func mapped<T where T:SomeProtocol>(dictionary: NSDictionary?, key: String) -> T? {
return nil
}
}
// Some struct
struct SomeStruct {
var someNumber: Double? = 0.0
}
extension SomeStruct: SomeProtocol {
init(dictionary: NSDictionary?) {
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
// OPTION 2: Writing this makes it work
// someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber!
}
}
// Test code
let test = SomeStruct(dictionary: NSDictionary(object: 1234.4567, forKey: "someNumber"))
if test.someNumber == 1234.4567 {
print("success \(test.someNumber!)")
} else {
print("failure \(test.someNumber)")
}
请注意,这是一个缺少mapped 函数的实际实现的示例,但结果是相同的,就这个问题而言,代码应该足够了。
编辑:我之前报告过这个问题,现在它被标记为已修复,所以希望在 Swift 3 中不再发生这种情况。
https://bugs.swift.org/browse/SR-574
【问题讨论】: