swift - 创建一个可复制的协议(protocol)默认初始化器

标签 swift protocols type-alias associated-types

我得到了这个函数:

public protocol ContentType {
    associatedtype T

    static var allTypes: [T] { get }
    static func getContentType(contentTypeId: String) -> T

    var contentTypeId: String? { get }
}

public protocol Copyable: class {
    associatedtype T

    static func copy(old: T, new: T)
}

public protocol CopyableContentType: class {
    associatedtype T
    init(existingContentType: T, newContentTypeId: String?)
}

我想为一个类提供一个默认的初始值设定项:

  • 符合ContentType
  • 符合可复制

对于上面的代码,我总是在所需的 init 中做同样的事情:调用实现类的复制函数。有什么方法可以在保留此初始化程序的同时省略跨类的重复代码吗?我想到了将其添加到协议(protocol)扩展中:

public extension CopyableContentType where Self: ContentType & Copyable {
    typealias T = Self // So wrong but I have no idea what to put here
                       // T should be the same T as the T usud in ContentType and Copyable
    init(existingContentType: T, newContentTypeId: String?) {
        Self.copy(old: existingContentType, new: self)
    }
}

但这会导致一些错误。我不知道在 typealias 中输入什么,我不能使用 associatedtypes。有什么方法可以提供调用复制函数的默认初始化程序吗?

最佳答案

I want to provide a default initializer for a class that:

  • Conforms to ContentType
  • Conforms to Copyable

假设您的意思是这样,我将尝试回答这个问题:

  • 您想提供 init(existingContentType: T, newContentTypeId: String?) 初始化程序的默认实现,如 ContentType 中的蓝图, 如果符合ContentType的类型也符合Copyable

首先让我们看一下您的Copyable 协议(protocol)。这可能是由于您的问题中遗漏了细节/用例,但我在这里看不到相关类型 T 的需要,因为协议(protocol)基本上是蓝图/ promise class 类型符合 Copyable,例如 TheClassType,将提供 static copy(from : TheClassType, to: TheClassType) function" — 其中符合类型 (TheClassType) 只是 Self。即:

protocol Copyable: class {
    static func copy(from: Self, to: Self)
}

同样适用于 ContentType:这里是否需要 associatedType,或者给定具体类型的 ContentType 是否只是自己打字;即 Self?在继续之前,让我们去掉与您的问题无关的部分:

protocol ContentType {
    var contentTypeId: String? { get }
}

现在,在任何初始化器复制(不是赋值——我们正在处理引用类型)任何self(例如self<的值类型成员)之前), self 必须已经初始化(或分配给)。因此,允许为 ContentTypeinit(existingContentType: Self, newContentTypeId: String?) 初始化程序提供默认实现(在符合 Copyable 的情况下>; Self 是一个 class 类型)——其中的实现旨在利用蓝图 copy(from: Self, to: Self) copyable 的 > - 符合 ContentType 的类型必须知道在复制步骤之前初始化自身的方法。即,在调用 copy(from:to) 方法。让我们简单地绘制蓝图 init():

protocol ContentType {
    var contentTypeId: String? { get set }
    init()
}

现在,由于 ContentType 蓝图了一个 contentTypeId 成员,并且复制初始化程序包含一个 newContentTypeId 参数,提供一个默认实现的初始化程序以 contentTypeId 作为其唯一参数;即 init(contentTypeId: String?):

extension ContentType {
    init(contentTypeId: String?) {
        self.init()
        self.contentTypeId = contentTypeId
    }
}

有了这个,我们可以提供默认实现的 init(existingContentType: Self, newContentTypeId: String?) 初始化器作为对 ContentType 的约束扩展,基于SelfCopyable:

extension ContentType where Self: Copyable {
    init(existingContentType: Self, newContentTypeId: String?) {
        self.init(contentTypeId: newContentTypeId)
        Self.copy(from: existingContentType, to: self)
    }
}

例子

综合以上:

protocol Copyable: class {
    static func copy(from: Self, to: Self)
}

protocol ContentType {
    var contentTypeId: String? { get set }
    init()
}

extension ContentType {
    init(contentTypeId: String?) {
        self.init()
        self.contentTypeId = contentTypeId
    }
}

extension ContentType where Self: Copyable {
    init(existingContentType: Self, newContentTypeId: String?) {
        self.init(contentTypeId: newContentTypeId)
        Self.copy(from: existingContentType, to: self)
    }
}

例子:

// Copyable content type
final class Foo: ContentType, Copyable {
    // Note that since all stored properties have initial values,
    // the compiler provides a synthesized initializer for init().
    var contentTypeId: String?
    var data = 0

    static func copy(from: Foo, to: Foo) {
        to.data = from.data
    }
}

let foo1 = Foo(contentTypeId: "foo1")
foo1.data = 42
let foo2 = Foo(existingContentType: foo1, newContentTypeId: "foo2")

print(foo1.contentTypeId ?? "None", foo1.data) // foo1 42
print(foo2.contentTypeId ?? "None", foo2.data) // foo2 42


// Non-copyable content type
final class Bar: ContentType {
    var contentTypeId: String?
} // Bar has no access to
  // init(existingContentType: Self, newContentTypeId: String?)

关于swift - 创建一个可复制的协议(protocol)默认初始化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51222634/

相关文章:

typescript - 我可以确定一个值是否与类型别名匹配吗?

module - 为什么 `type alias` 是在另一个模块中以相同方式定义的类型?

arrays - Swift:删除文档字段Firestore(云数据库)内字典中的元素

php - swift 3.0 中的播放器 ID 格式问题

swift - 我们什么时候可以开始向 iOS App Store 提交使用 Swift 编程语言编写的应用程序?

ios - UICollectionView 的水平流

logging - 构造系统日志消息时的乱码输出

swift - 如何在Struct中实现协议(protocol)可选方法?

swift - 协议(protocol)实现 init 的访问控制

swift - 为整个项目定义一个类型别名