代码之家  ›  专栏  ›  技术社区  ›  J. Doe

创建可复制的协议默认初始值设定项

  •  0
  • J. Doe  · 技术社区  · 6 年前

    我有这个功能:

    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
    • 符合 Copyable

    使用上面的代码,我总是在所需的init中执行同样的操作:调用实现类的copy函数。在保持初始值设定项的同时,是否有任何方法可以在类之间省略此重复代码?我想把它添加到协议扩展中:

    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。有什么方法可以提供一个调用copy函数的默认初始值设定项吗?

    1 回复  |  直到 6 年前
        1
  •  2
  •   dfrib    6 年前

    我想为一个类提供一个默认的初始化器:

    • 符合 ContentType
    • 符合 Copyable

    假设你的意思是:

    • 你想提供一个 默认实现 一个 init(existingContentType: T, newContentTypeId: String?) 初始值设定项,如蓝图所示 内容类型 我是说, 如果 符合 内容类型 也符合 可复制 是的。

    让我们先看看你的 可复制 协议。这可能是由于在您的问题中遗漏了细节/用例,但是我不认为需要相关类型 T 这里,协议基本上是蓝图/承诺 “在 class 类型符合 可复制 ,例如。 TheClassType ,将提供 static copy(from: TheClassType, to: TheClassType) 函数 其中一致类型( 类别 )只是 Self 是的。即。:

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

    同样适用于 内容类型 :是否需要 associatedType 在这里,还是 内容类型 一个给定的具体类型的简单的类型本身;即。 自我 是吗?在继续之前,先去掉与您的问题无关的部分:

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

    现在,在任何初始值设定项复制(不是赋值-我们正在处理引用类型)任何内容之前 进入之内 self (例如,值类型成员 自己 )我是说, 自己 必须已初始化(或分配给)。所以允许为 init(existingContentType: Self, newContentTypeId: String?) 的初始值设定项 内容类型 (如果符合 可复制 (二) 自我 是一个 类型)如果实现的目的是使用蓝图 copy(from: Self, to: Self) 属于 copyable “符合 内容类型 必须知道初始化程序本身的方法 先前的 复制步骤。也就是说, 内容类型 需要设计一些可用于初始化的初始值设定项 自己 在调用 copy(from:to) 方法。让我们简单地设计一下 init() 以下内容:

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

    现在,作为 内容类型 蓝图A contentTypeId 成员,并且复制初始值设定项包含 newContentTypeId 参数,可以为默认实现的初始值设定项提供 内容类型ID 作为它唯一的参数;即 init(contentTypeId: String?) 以下内容:

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

    有了它,我们可以提供 init(生存内容类型:Sub,NeNeCuthType ID:String?) 初始值设定项作为 内容类型 基于 自我 可复制 以下内容:

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