swift - 定义一个将 Collection 作为属性的协议(protocol)

标签 swift

我想定义一个协议(protocol),该协议(protocol)定义了“Collection”类型的变量“序列”。我想要这样,因为我有几种一致的类型,它们都将保存不同类型的数组。示例:

protocol BioSequence {
    associatedtype T
    var sequence: Collection { get }

    // Will also implement conformance to Collection and redirect all Collection functions to the property "sequence". This is because my types that conform to BioSequence are just wrappers for an array of Nucleotide or AminoAcid with some extra functionality
}

struct DNASequence: BioSequence {
    // Will hold "sequence" of type [Nucleotide]
}

struct AminoSequence: BioSequence {
    // Will hold "sequence" of type [AminoAcid]
}

为什么我想要这个?因为我只需要在 BioSequence 中实现一次对“Collection”的一致性,并且所有符合的类型都会自动继承它。另外,我可以自由地在符合类型上添加额外的功能。

现在,当我像上面的代码一样尝试时,编译器会说:“协议(protocol)集合只能用作通用约束”。是的,我用谷歌搜索了这个错误的含义,但是我如何才能真正修复它以使我的代码正常工作,就像我想要的那样。或者根本不可能做我想做的事?

谢谢。

最佳答案

您可以通过在协议(protocol)中使用 linkedtype 轻松实现此目的,该协议(protocol)可以约束为 Collection,从而允许符合类型在特定类型满足要求时满足具体类型的要求。采用协议(protocol)。

例如:

protocol CollectionWrapper : Collection {
    associatedtype Base : Collection
    var base: Base { get }
}

extension CollectionWrapper {

    var startIndex: Base.Index {
        return base.startIndex
    }

    var endIndex: Base.Index {
        return base.endIndex
    }

    func index(after i: Base.Index) -> Base.Index {
        return base.index(after: i)
    }

    subscript(index: Base.Index) -> Base.Iterator.Element {
        return base[index]
    }

    // Note that Collection has default implementations for the rest of the
    // requirements. You may want to explicitly implement them and forward them to
    // the base collection though, as it's possible the base collection implements
    // them in a more efficient manner (e.g being non random access and having
    // a stored count).
}

// S adopts CollectionWrapper and satisfies the 'Base' associatedtype with [String].
struct S: CollectionWrapper {
    var base: [String]
}

let s = S(base: ["foo", "bar", "baz"])
print(s[1]) // "bar"

关于您的评论:

If I want to use this like that: let a: CollectionWrapper = S() [...] this leaves me with "Protocol can only be used as a generic constraint" again.

问题是您当前无法谈论具有关联类型要求的协议(protocol),因为用于满足这些要求的类型对于编译器来说是未知的( this isn't a technical limitation though )。您可以使用 Swift 的 AnyCollection 来解决这个问题输入删除器以使用给定元素类型包装任意Collection

例如:

let a = AnyCollection(S(base: ["foo", "bar", "baz"]))

如果您需要满足 CollectionWrapper 的其他协议(protocol)要求,则必须实现自己的类型删除器才能实现。请参阅Rob's answer here了解如何解决这个问题。

关于swift - 定义一个将 Collection 作为属性的协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42099186/

相关文章:

xcode - 与屏幕截图和文本一起共享 URL

ios - 打开设置 iOS 8 URL

ios - AVCaptureSession 图像是屏幕大小

ios - 如何将 Swift String 桥接到 Objective C NSString?

iphone - Segue被执行了两次

ios - swift:swift 中的 SnapKit 不起作用

ios - 旋转后接收两个不同高度的键盘

swift - MapView 用户的当前位置常规 Pin

ios - UITableView 行在 UITableViewHeaderSection 下滑动

ios - init 不调用自定义类 swift