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

What is the correct way to reinterpret an entity in Swift?

有些情况下你必须处理某种类型的结构,但上游 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 中的结构的规范方法是什么?

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

In Swift 3, the user should explicitly rebind memory to a different type:

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

另一种方法

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

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