我正在尝试构建一个可以从String初始化的通用结构。
最小例子:
struct Example<T> {
var data: T
init(fromString string: String) {
data = T(string)
}
}
这自然会失败,因为我们必须确保T可以是来自String的init()。
我找不到这个协议,所以我试图创建它:
protocol InitializableWithString { init?(_: String) }
struct Example<T: InitializableWithString> { ... }
但是尝试使用Int:
let testVar = Example<Int>(fromString: "12")
错误:类型'Int'不符合协议'InitializableWithString'
但Ints确实有一个可用的初始化器,它接受一个String参数。
> let intFromString = Int("12")
intFromString: Int? = 12
有没有办法完成我在这里要做的事情?
答案 0 :(得分:1)
AFAIK表示可以使用String
创建的类型的协议不存在。
你定义了自己的,但是有一些错误。
protocol InitializableWithString {
init?(string:String)
}
Int
符合InitializableWithString
Int
结构体有一个初始化程序,用于从Int
创建String
,在我们编写时使用它
Int("123")
此初始化程序具有以下签名
public init?(_ text: String, radix: Int = default)
此解决方案的缺失部分是Int
,以使其符合InitializableWithString
,如下所示
extension Int: InitializableWithString {
init?(string: String) {
self.init(string)
}
}
init
的{{1}}同样可以由于Example
的初始值设定项可用,因此您无法构建InitializableWithString
类型。在这种情况下,T
init`应该做什么?最简单的解决方案是让它失败,所以
Example
现在你可以写
了struct Example<T where T: InitializableWithString> {
var data: T
init?(string: String) {
guard let data = T(string: string) else { return nil }
self.data = data
}
}
现在,您可以使更多类型符合let example = Example<Int>(string: "123")
if let example = example {
print(example.data)
}
,然后使用它们来构建新的InitializableWithString
值。
答案 1 :(得分:1)
问题是你没有明确地将Int
与你的InitializableWithString
协议相符,因此即使它可能含蓄地符合,Swift的类型系统也不会认识到这一点。
您可以通过扩展程序明确地遵守它:
extension Int : InitializableWithString {}
但是,我们仍然会收到错误:
Type'Int'不符合协议'InitializableWithString'
问题现在是Int
可以使用String
进行初始化,而through this initialiser则是,它有两个参数 - {{ 1}}参数恰好有一个默认值:
radix:
因此,Swift无法识别/// Construct from an ASCII representation in the given `radix`.
///
/// If `text` does not match the regular expression
/// "[+-]?[0-9a-zA-Z]+", or the value it denotes in the given `radix`
/// is not representable, the result is `nil`.
public init?(_ text: String, radix: Int = default)
可以满足Int
要求。因此,解决方案是实现满足此要求的初始化程序,并使用默认的init?(_: String)
值将调用转发到init?(_:radix:)
初始化程序:
radix
或者,如果您还希望能够处理非十进制数字表示,则将协议更改为需要extension Int : InitializableWithString {
init?(_ str: String) {
self.init(_:radix:)(str) // the (_:radix:) is used in order to disambiguate
}
}
参数:
radix:
有了这个,你不需要实现额外的初始化,因为protocol InitializableWithString {
init?(_: String, radix:Int)
}
直接满足了这个要求。