将 Collection 的子序列转换为 String

Convert subsequence of Collection to String

我想将集合的子序列转换为字符串。例如,这个函数收集集合的前两个字节并将其转换为字符串。

func convert<T: Collection>(_ c: T) -> String 
    where T.Iterator.Element == UInt8 
{
    let start = c.startIndex
    let end = c.index(after: start)
    return String(bytes: c[start ... end], encoding: String.Encoding.utf8)!
}

这会导致此错误:

error: ambiguous reference to member 'subscript'
        return String(bytes: c[start ... end], encoding: String.Encoding.utf8)!
                             ~^~~~~~~~~~~~~~~
Swift.Collection:167:12: note: found this candidate
    public subscript(position: Self.Index) -> Self.Iterator.Element { get }
           ^
Swift.Collection:189:12: note: found this candidate
    public subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get }
           ^
Swift.Collection:25:12: note: found this candidate
    public subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }
           ^
Swift.IndexableBase:54:12: note: found this candidate
    public subscript(position: Self.Index) -> Self._Element { get }
           ^
Swift.IndexableBase:63:12: note: found this candidate
    public subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get }
           ^
Swift.Indexable:23:12: note: found this candidate
    public subscript(bounds: ClosedRange<Self.Index>) -> Self.SubSequence { get }
           ^
Swift.Indexable:23:12: note: found this candidate
    public subscript(bounds: CountableRange<Self.Index>) -> Self.SubSequence { get }
           ^
Swift.Indexable:45:12: note: found this candidate
    public subscript(bounds: CountableClosedRange<Self.Index>) -> Self.SubSequence { get }

我在这里错过了什么? :-)

目前,CollectionSubSequence 不能保证与集合本身具有相同的元素类型,这是由于 associatedtype 的限制。

事实上,SE-0142: Permit where clauses to constrain associated types 的动机之一是允许约束 associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element,这将加强这种关系。

尽管在这种特殊情况下,由于您首先没有使用 T.Iterator.Element == UInt8 约束,您可以改为约束 T.SubSequence.Iterator.Element(感谢@MartinR):

func convert<T: Collection>(_ c: T) -> String
    where T.SubSequence.Iterator.Element == UInt8 {

    let start = c.startIndex
    let end = c.index(after: start)

    // please consider handling the case where String(bytes:encoding:) returns nil.
    return String(bytes: c[start ... end], encoding: String.Encoding.utf8)!
}

(在更一般的情况下,您还需要将 T.Iterator.Element 约束到给定类型,您可能希望添加 T.SubSequence.Iterator.Element == T.Iterator.Element 作为附加约束)。