代码之家  ›  专栏  ›  技术社区  ›  Andrew Lipscomb

swift-使用协议强制转换数组与ArraySlice

  •  1
  • Andrew Lipscomb  · 技术社区  · 6 年前

    protocol MyProtocol {}
    extension Int: MyProtocol {}
    
    let a: Array<MyProtocol> = Array<Int>()
    let b: ArraySlice<MyProtocol> = a[...]
    let c: Array<Int> = a as! Array<Int>
    let d: ArraySlice<Int> = b as! ArraySlice<Int>
    

    d Cast from 'ArraySlice<MyProtocol>' to unrelated type 'ArraySlice<Int>' always fails .

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

    这基本上是由于Swift中的通用差异是如何工作的。

    Only few types are variant in Swift ,包括 Array<T> Set<T> . 大多数其他类型以及您定义的类型都是不变的。

    不变性意味着 T<A> T<B> 是不相关的类型即使 A B 是相关的。

    数组<T> 设置<T> 是协变的,这意味着 Array<A> 可以分配给类型的变量 Array<B> A. 是的子类型 B . 您可以使用 as! .

    ArraySlice<T>

    let d: ArraySlice<Int> = ArraySlice(b.map { $0 as! Int })
    
        2
  •  0
  •   Andrew Lipscomb    6 年前

    作为@Sweeper对那些寻找类型flexible performant copy by ref数组的人的正确答案的补充答案,我最终推出了一个解决方案,它将一个数组封装在一个类中,并公开了一个数组的一些API。

    class ArrayReference<T>: Collection {
        private(set) var array : Array<T>
    
        init(_ encapsulating: Array<T>? = nil) {
            self.array = encapsulating ?? []
        }
    
        var startIndex: Int {
            get {
                return array.startIndex
            }
        }
    
        var endIndex: Int {
            get {
                return array.endIndex
            }
        }
    
        var count : Int {
            get {
                return array.count
            }
        }
    
        func index(after i: Int) -> Int {
            return array.index(after: i)
        }
    
        subscript (index: Int) -> T {
            get { return array[index] }
            set(newValue) { array[index] = newValue }
        }
    
        func append(_ newValue: T) {
            array.append(newValue)
        }
    
        func removeAll() {
            array.removeAll()
        }
    
        var first: T? {
            if array.count > 0 {
                return array[0]
            } else {
                return nil
            }
        }
    
        var last: T? {
            if array.count > 0 {
                return array[array.count - 1]
            } else {
                return nil
            }
        }
    
        func asType<C>(_ type: C.Type) -> ArrayReference<C>? {
            if let array = self.array as? Array<C> {
                return ArrayReference<C>(array)
            } else {
                return nil
            }
        }
    }
    
    extension ArrayReference: Equatable where T: Equatable {
        static func == (lhs: ArrayReference<T>, rhs: ArrayReference<T>) -> Bool {
            if lhs.count == rhs.count {
                var equal = true
                for (lhs, rhs) in zip(lhs, rhs) {
                    equal = equal && (lhs == rhs)
                }
                return equal
            } else {
                return false
            }
        }
    }