快速便利初始化和通用类

标签 swift generics init

我在创建一个方便的 init 方法时遇到问题,该方法然后使用泛型类型参数在类上调用指定的 init。这是 swift 3.1 XCode 版本 8.3.2 (8E2002) Playground

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

如果不存在 convenience init,那么/*: Client */部分下的代码将毫无问题地编译和执行。如果我添加了 convenience init,我会得到以下编译错误:

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

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

最佳答案

通用占位符对给定通用类型的使用感到满意 - 因此在您的 convenience init 中,您不能假设 T 是一个部分。它是符合 A 的任意具体类型。

例如,调用者定义一个

是完全合法的
struct SomeOtherSection : A {...}

然后使用 TSomeOtherSection 调用您的便利初始化程序。

这种情况下的解决方案很简单,您只需在 DataSource 的扩展中添加您的便利初始化程序,其中 T 被限制为 Section – 因此允许您使用[Section]
调用init(sections:):

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

关于快速便利初始化和通用类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44066573/

相关文章:

ios - iPhone:将imageView设置在图像的透明部分

ios - 带有来自传递值的可选 SubView 的 swift UIView 子类

json - 使用 Swift 4 的 Decodable 解码 Void

ios - 手动将 nil 设置为 swift 对象以避免保留循环?

ios - RxSwift : Deliver the first item immediately, 去抖以下项目

function - Typescript 中函数的通用返回类型

java - Java使用反射创建泛型参数化类

java - 我无法为 AsyncTask 的结果参数设置上限

emacs - Emacs的init.el文件未加载

c# - 有趣的 ASP.NET 生命周期事件触发错误