Swift 4中具有不同类型的递归通用结构

时间:2018-03-29 19:30:04

标签: swift generics

struct Lock<Element: Hashable> {

    var element: Element

    init(_ element: Element, _ args:[Lock<Element>]? = nil) {
        self.element = element
    }
}

是否可以修改这种结构,以便能够在参数中使用不同的Element类型调用init()?

Lock("element", [Lock("100")])没关系

Lock("element", [Lock(100)])这会导致错误:无法转换类型&#39; Int&#39;预期参数类型&#39;锁定&lt; _&gt;&#39;

3 个答案:

答案 0 :(得分:1)

您有2个选项可以执行此操作。

改进@ Cristik的答案的简单解决方案是让另一个初始化者不期望另一个通用参数:

struct Lock<Element> {
    var element: Element

    init(_ element: Element) {
        self.element = element
    }
    init<T>(_ element: Element, _ args: [Lock<T>]?) {
        self.init(element)
    }
}

然后,您可以获得上面所需的代码,但却丢失了Element符合Hashable的信息。

您的第二个选择是使用protocol创建associatedtype。使用具有2 init s的类似技巧,除了明确定义类型外,您可以执行相同的操作:

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)
    }
}

然后你可以创建这样的锁:

let stringStringLock = HashableLock("element", [HashableLock("100")])
let stringIntLock = HashableLock("element", [IntLock(100)])

第一个版本更清洁,但更具限制性。这取决于您使用哪一个,取决于您的需求。

答案 1 :(得分:0)

这不可能。

原因是Element被分配给init中用于元素参数的类型。现在,只要Element出现在结构中,就必须使用相同的类型,但如果你想要通用类型Lock,那么你需要声明另一个泛型类型。

这里的问题是,通过向Lock添加另一种通用类型(即Lock<Element, AnotherElement>),现在Lock中的init需要指定两种泛型类型等等。

答案 2 :(得分:0)

通过使初始化程序通用,您可能会获得更好的结果:

struct Lock<Element: Hashable> {

    var element: Element

    init<T>(_ element: Element, _ args:[Lock<T>]? = nil) {
        self.element = element
    }
}