在某些情况下,您必须处理某种类型的结构,但上游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中重新解释结构的规范方法是什么?
答案 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()
的构造函数,但可能
临时存储的地址,并不能保证
当构造函数返回并关闭时它仍然有效
叫做。