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]。
不同代码的答案是正确的,但它也是重要的是要明白,为什么你不能只是重新解释数据,而不 东西 做一个O(n)的转换行走,虽然在一个盒子包装的每个元素。
[A]是一个数组,元素大小为A。因此,或多或少A[1]都在内存位置A[0] + sizeof(A)(这不是完全正确,但假装是;它将使事情变得更简单)。
[A]
A
A[1]
A[0] + sizeof(A)
[Test]必须能够容纳符合协议的 任何内容 。可能是的大小A,可能是的大小B,后者更大。为此,它创建了一个包含“符合条件Test” 的框。这个盒子的大小是已知的,它可能必须堆放它所指向的对象(或者可能不是;取决于),但是它的大小不会A和和相同B,因此[Test]内存中的布局必须与[A]或的布局不同[B]。
[Test]
B
Test
[B]
现在as [Test]可以做O(n)为您走,然后立即强制复制。或将复制延迟到您第一次修改某项内容之前,但这会复杂得多,并且会将O(n)(可能是昂贵的,可能是内存分配)事件埋在一个内部as,感觉像应该是O(1)并且不分配内存。因此,有理由不这样做。
as [Test]
as
总有一天,他们可能会这样做,以使调用方的事情变得更简单,但是性能和复杂性都有代价,因此今天不这样做,您需要自己制作地图。
如果您想更深入地研究这些内容,并详细了解此框的工作方式(并且不要“假装比现在更简单”),请参阅WWDC 2016中的了解Swift性能。