[英]Recursive generic structs with different types in Swift 4
struct Lock<Element: Hashable> {
var element: Element
init(_ element: Element, _ args:[Lock<Element>]? = nil) {
self.element = element
}
}
Is it possible to modify this kind of struct to be able call init() with different Element
types in arguments? 是否可以修改这种结构,以便能够在参数中使用不同的
Element
类型调用init()?
Lock("element", [Lock("100")])
it's ok Lock("element", [Lock("100")])
没关系
Lock("element", [Lock(100)])
this causes an error: Cannot convert value of type 'Int' to expected argument type 'Lock<_>' Lock("element", [Lock(100)])
这会导致错误: 无法将“Int”类型的值转换为预期的参数类型“Lock <_>”
You have 2 options for doing this. 您有2个选项可以执行此操作。
The simple solution, improving on @Cristik's answer, is to have another initialiser that doesn't expect another generic parameter: 改进@ Cristik的答案的简单解决方案是使用另一个不期望另一个通用参数的初始化器:
struct Lock<Element> {
var element: Element
init(_ element: Element) {
self.element = element
}
init<T>(_ element: Element, _ args: [Lock<T>]?) {
self.init(element)
}
}
You can then have the code you want above, but you lose the information that Element
conforms to Hashable
. 然后,您可以获得上面所需的代码,但是您将丢失
Element
符合Hashable
的信息。
Your second option is to create a protocol
using an associatedtype
. 您的第二个选择是使用
associatedtype
创建protocol
。 Using a similar trick with having 2 init
s, you can do the same except explicitly defining the types: 使用具有2个
init
的类似技巧,除了明确定义类型之外,您可以执行相同的操作:
protocol Lock {
associatedtype Element
init(_ element: Element)
init<T>(_ element: Element, _ args: [T]?) where T: Lock
}
struct HashableLock<H: Hashable>: Lock {
typealias Element = H
var element: Element
init(_ element: Element) {
self.element = element
}
init<T>(_ element: Element, _ args: [T]?) where T: Lock {
self.init(element)
}
}
struct IntLock: Lock {
typealias Element = Int
var element: Int
init(_ element: Int) {
self.element = element
}
init<T>(_ element: Int, _ args: [T]?) where T: Lock {
self.init(element)
}
}
Then you can create locks like this: 然后你可以创建这样的锁:
let stringStringLock = HashableLock("element", [HashableLock("100")])
let stringIntLock = HashableLock("element", [IntLock(100)])
The first version is a lot cleaner but it's more limiting. 第一个版本更清洁,但它更具限制性。 It's up to you which one to use, depends on your needs.
这取决于您使用哪一个,取决于您的需求。
This cannot be done. 这是不可能做到的。
The reason is that Element
gets assigned to the type used for the element parameter in init
. 原因是
Element
被赋予init
用于element参数的类型。 Now that same type has to be used whenever Element
appears in the struct but if you want the generic type of Lock
to be anything else, you'll need to declare another generic type. 现在,只要
Element
出现在struct中,就必须使用相同的类型,但是如果你想要Lock
的泛型类型,你需要声明另一个泛型类型。
The problem here is that by adding another generic type to Lock
(ie Lock<Element, AnotherElement>
) is that now the Lock
in your init
will need to specify two generic types, and so on. 这里的问题是,通过向
Lock
添加另一个泛型类型(即Lock<Element, AnotherElement>
),现在init
的Lock
将需要指定两个泛型类型,依此类推。
You might get better results by making the initializer generic: 通过使初始化程序通用,您可能会获得更好的结果:
struct Lock<Element: Hashable> {
var element: Element
init<T>(_ element: Element, _ args:[Lock<T>]? = nil) {
self.element = element
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.