快速便捷初始化和通用类

use*_*806 3 generics init swift

我在创建方便的init方法时遇到问题,该方法随后在具有泛型类型参数的类上调用指定的init。这是Swift 3.1 XCode版本8.3.2(8E2002)游乐场

protocol A {
    var items: [String] { get set }
    func doSomething()
}

struct Section : A {
    var items: [String] = []

    func doSomething() {
        print("doSomething")
        items.forEach { print($0) }
    }
}

class DataSource<T: A> {
    var sections: [T]

    init(sections: [T]) {
        self.sections = sections
    }

    func process() {
        sections.forEach { $0.doSomething() }
    }

    convenience init() {
        var section = Section()
        section.items.append("Goodbye")
        section.items.append("Swift")

        self.init(sections: [section])
    }
}

/*: Client */
var section = Section()
section.items.append("Hello")
section.items.append("Swift")

let ds = DataSource(sections: [section])
ds.process()
Run Code Online (Sandbox Code Playgroud)

如果不存在便利初始化,则/ *:Client * /部分下面的代码将编译并执行而不会出现问题。如果我添加了便利初始化,则会出现以下编译错误:

cannot convert value of type '[Section]' to expected argument type '[_]'
        self.init(sections: [section])
Run Code Online (Sandbox Code Playgroud)

我不认为这将是一个问题,因为在方便的初始化中,我正在创建一个Section结构,该结构实现协议A,该协议A满足DataSource类的一般约束。便利初始化正在执行与客户端代码相同的操作,但无法将[Section]转换为[A]。这是初始化排序问题吗?

Ham*_*ish 5

通用占位符对给定通用类型的使用感到满意–因此,在您内部convenience init,您不能假定TSection。这是符合的任意具体类型A

例如,调用方定义一个

struct SomeOtherSection : A {...}
Run Code Online (Sandbox Code Playgroud)

然后调用您的方便与初始化剂TSomeOtherSection

在这种情况下,解决方法很简单,只需将它添加您的方便初始化器中的延伸DataSource,其中T被约束为被Section-因此允许你
打电话init(sections:)[Section]

extension DataSource where T == Section {

    convenience init() {
        var section = Section()
        section.items.append("Goodbye")
        section.items.append("Swift")

        self.init(sections: [section])
    }
}

// ...

// compiler will infer that T == Section here.
let ds = DataSource()
Run Code Online (Sandbox Code Playgroud)