在 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()
的构造函数,但 可能 是
临时存储的地址,并且不能保证
当构造函数返回并且闭包时它仍然有效
叫做。
有些情况下你必须处理某种类型的结构,但上游 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()
的构造函数,但 可能 是
临时存储的地址,并且不能保证
当构造函数返回并且闭包时它仍然有效
叫做。