在此代码段中
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
警告。
为什么切片不能以与原始数组相同的方式进行转换?可以修改此代码段以将数组转换行为赋予Slice吗?
答案 0 :(得分:1)
这基本上是由于Swift中泛型方差的工作原理。
Only few types are variant in Swift,包括Array<T>
和Set<T>
。大多数其他类型以及您定义的类型都是不变的。
不变性意味着T<A>
和T<B>
是不相关的类型,即使A
和B
是相关的。
Array<T>
和Set<T>
是协变的,这意味着如果Array<A>
是{的子类型,则可以将Array<B>
分配给类型A
的变量。 {1}}。您可以使用B
强制其沿另一方向移动(就像您在第三行中所做的那样)。
as!
只是不变的。您需要执行以下操作才能转换:
ArraySlice<T>
答案 1 :(得分:0)
作为@Sweeper的正确答案的附录答案,此方法适用于正在寻找类型灵活的性能按引用复制数组的人,我最终推出了一种将数组包装在类中并公开一些API的解决方案用于数组。
这不是一个很好的解决方案,但是可以满足我的需要。 Boo Apple没有为这类事情保持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
}
}
}