仅使用协议在类型之间转换?

时间:2017-10-14 14:03:09

标签: swift casting protocols

我有2 structs只与协议相关。我试图在这两种类型之间进行转换,因为它们共享协议,但是我遇到了运行时错误。

这就是我要做的事情:

protocol A {
    var id: String { get }
    var name: String { get }
    var isActive: Bool { get set }
}

struct Entity: A {
    let id: String
    var name: String
    var isActive: Bool

    func someFun() {
        print("\(name), active: \(isActive)")
    }
}

struct ViewModel: A {
    let id: String
    var name: String
    var isActive: Bool
}

let vm = ViewModel(id: "abc", name: "John Doe", isActive: true)
let pt = vm as A
let et = pt as! Entity
print(et.someFun()) //crash

我得到的错误是:

Could not cast value of type '__lldb_expr_87.ViewModel' (0x111835638) to '__lldb_expr_87.Entity' (0x111835550).

这真是一个真正的无赖,因为如果我有数百万条记录,我不想循环遍历每一条记录,一个接一个地手动转换。我希望隐晦地像这样神奇地投下:

let entity = vm as A as Entity
let entities = vms as [A] as [Entity]

任何具有性能意识的方法在边界之间传递对象而不循环遍历每个对象?

1 个答案:

答案 0 :(得分:0)

正如vadian在评论中指出的那样,你不能这样做。要通过类型转换来执行您要执行的操作,您需要执行以下操作:

let entity = Entity(id: vm.id, name: vm.name, isActive: vm.isActive)

let entities = vms.map {
  return Entity(id: $0.id, name: $0.name, isActive: $0.isActive
}

您崩溃的原因是,类型转换不会更改对象实际具有的属性和方法,只有他们有权访问的方法和属性。如果您执行了以下操作,则会失去对someFun()方法的访问权限:

let entityAsA = Entity(id: "id", name: "name", isActive: true) as A

但是,以下内容将编译并运行而不会崩溃:

(entityAsA as! Entity).someFun()

因此,当您尝试从ViewModel转换为A到Entity时,它不会更改在内存中创建值的方式(无法访问名为someFun()的函数),并且每次都会崩溃。 / p>