【问题标题】:Type conversion when using protocol in Swift在 Swift 中使用协议时的类型转换
【发布时间】:2016-07-15 11:20:23
【问题描述】:
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]

"let f = e as [Test], let g = e as! [Test]" 总是出错。我有一个功能,我必须将 [Test] 发送到其中。 Convert A to Test 易于使用。但是说到Array,我必须遍历所有的数据。有什么好方法可以将[A]转换为[Test]。

【问题讨论】:

    标签: swift


    【解决方案1】:

    Code Different 的答案是正确的,但同样重要的是要理解为什么你不能在没有 something 进行 O(n) 转换以遍历并将每个元素包装在一个盒子中的情况下重新解释数据.

    [A] 是一个数组,其元素大小为A。所以,或多或少,A[1] 位于内存位置 A[0] + sizeof(A)(这并不完全正确,但假装是这样;它会让事情变得更简单)。

    [Test] 必须能够保存符合协议的任何东西。它可能是A 的大小,也可能是B 的大小,后者更大。为了实现这一点,它创建了一个包含“符合Test 的东西”的盒子。盒子的大小是已知的,它可能必须堆分​​配它指向的东西(或者可能不是;取决于),但它不会与AB 的大小相同,所以[Test]在内存中的布局必须不同于[A][B]的布局。

    现在as [Test] 可以为您执行 O(n) 步行并立即强制复制。或者它会延迟复制,直到你第一次修改某些东西,但这会更复杂,它会在as 中隐藏一个 O(n) (可能是昂贵的,可能是内存分配)事件,感觉应该是 O (1) 并且不分配内存。所以我们有理由不这样做。

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

    如果您想更深入地研究这些东西,并详细了解这个盒子的工作原理(而不是“假装它比实际简单”),请参阅 WWDC 2016 的 Understanding Swift Performance

    【讨论】:

    • 伟大的洞察力,我喜欢看到这些事情背后的根本原因
    • 从 Swift 3(甚至 Swift 2.3?)开始,您可以将整个数组转换/转换为协议类型的数组。
    【解决方案2】:

    您不能像那样批量转换数组。使用map:

    let f = e.map { $0 as Test } // f is now a [Test] array
    

    【讨论】:

    • 可悲的是,为什么我不允许将 [A] 直接转换为 [Test]。
    • 这个你得问苹果的编译团队
    • 好消息是你可以!他们在今年的 WWDC 上就此发表了演讲。请参阅了解 Swift 性能。
    • 对不起;我的意思是你可以问编译器团队(因为他们发表了一个回答问题的演讲)。
    猜你喜欢
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    相关资源
    最近更新 更多