一尘不染

在Swift中使用协议时的类型转换

swift

protocol Test{

    var t: Int {set get}

}

struct A: Test{

    var t: Int

}

struct B: Test{

    var t: Int
    var s: String

}

let a = A(t: 1)
let b = B(t: 2, s: "1")

let c = a as Test

let d: [Test] = [a, b]

let e: [A] = [a, a]

let f = e as [Test]

let g = e as! [Test]

“让f = e为[测试],让g =
e为![测试]”总是会出错。我有一个必须发送[Test]到的功能。将A转换为Test易于使用。但是当涉及到数组时,我必须遍历所有数据。有什么好的方法可以将[A]转换为[Test]。


阅读 178

收藏
2020-07-07

共1个答案

一尘不染

不同代码的答案是正确的,但它也是重要的是要明白,为什么你不能只是重新解释数据,而不 东西 做一个O(n)的转换行走,虽然在一个盒子包装的每个元素。

[A]是一个数组,元素大小为A。因此,或多或少A[1]都在内存位置A[0] + sizeof(A)(这不是完全正确,但假装是;它将使事情变得更简单)。

[Test]必须能够容纳符合协议的 任何内容 。可能是的大小A,可能是的大小B,后者更大。为此,它创建了一个包含“符合条件Test
的框。这个盒子的大小是已知的,它可能必须堆放它所指向的对象(或者可能不是;取决于),但是它的大小不会A和和相同B,因此[Test]内存中的布局必须与[A]或的布局不同[B]

现在as [Test]可以做O(n)为您走,然后立即强制复制。或将复制延迟到您第一次修改某项内容之前,但这会复杂得多,并且会将O(n)(可能是昂贵的,可能是内存分配)事件埋在一个内部as,感觉像应该是O(1)并且不分配内存。因此,有理由不这样做。

总有一天,他们可能会这样做,以使调用方的事情变得更简单,但是性能和复杂性都有代价,因此今天不这样做,您需要自己制作地图。

如果您想更深入地研究这些内容,并详细了解此框的工作方式(并且不要“假装比现在更简单”),请参阅WWDC
2016中的了解Swift性能

2020-07-07