在Swift中重新解释实体的正确方法是什么?

时间:2017-08-08 07:00:02

标签: swift swift3 unsafe-pointers

在某些情况下,您必须处理某种类型的结构,但上游API要求您通过指向其他位置的其他类型的指针来呈现它。

例如,Unix Bind期望它的第二个参数是指向sockaddr的指针,而构造函数应该是sockaddr_in

现在我坚持使用两层with*

var sa = sockaddr_in(/* ... */)

withUnsafePointer(to: &sa) { _sa in
  _sa.withMemoryRebound(to: sockaddr.self, capacity: 1) { __sa in
    let err = bind(fd, __sa, socklen_t(saSize))
    precondition(err == 0)
  }
}

但是,我对这种方法的嘈杂感到沮丧。当我在指针类型之间使用unsafeBitCast时:

bind(fd, unsafeBitCast(__sa, to: UnsafeMutablePointer<sockaddr>.self), socklen_t(saSize))

然后编译器警告我不要这样做,并建议使用withMemoryRebound

当我使用就地构造的指针时:

UnsafeMutablePointer(mutating: &sa).withMemoryRebound(to: sockaddr.self, capacity: 1) { _sa in
  let err = bind(fd, _sa, socklen_t(saSize))
  precondition(err == 0)
}

然后它的工作原理与初始版本一样,并且让我们了解了一个级别的嵌套。虽然看起来比with*更脆弱。另外还不清楚,如果就地指针是正确的方法,为什么withUnsafePointer甚至存在。

话虽如此,在Swift中重新解释结构的规范方法是什么?

1 个答案:

答案 0 :(得分:2)

您的第一种方法是正确的,使用withUnsafePointer()withMemoryRebound(),从各种例子可以看出 在UnsafeRawPointer Migration中提供,例如

  

在Swift 3中,用户应该明确地将内存重新绑定到另一个内存   类型:

let result = withUnsafePointer(to: &addr) {
  // Temporarily bind the memory at &addr to a single instance of type sockaddr.
  $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
    connect(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
  }
}

另一种方法

UnsafeMutablePointer(mutating: &sa).withMemoryRebound(...) { ... }

对我来说很脆弱。 sa作为inout参数传递给 UnsafeMutablePointer()的构造函数,但可能 临时存储的地址,并不能保证 当构造函数返回并关闭时它仍然有效 叫做。