Swiftのポインタの変換について試す
概要
- SwiftのポインタにおいてUnsafeMutablePointerはUnsafePointerとして関数の引数に渡すことができる
- これは暗黙のアップキャストによるものらしい
- これだけ見た単純な理解だとMutableなポインタはImmutableなポインタ型として振る舞える?
- 上記を検証したい
Swiftのポインタの仕様
おもちさんの記事を見ると基本のポインタ型としてMutableとImmutableでペアとして以下のようにまとめられそう
Mutable | Immutable |
---|---|
UnsafeMutablePointer<T> | UnsafePointer<T> |
UnsafeMutableRawPointer | UnsafeRawPointer |
UnsafeMutableBufferPointer<T> | UnsafeBufferPointer<T> |
UnsafeMutableRawBufferPointer | UnsafeRawBufferPointer |
つまり冒頭の話通りであればMutableからImmutableなポインタに明示的に変換せずとも関数に引数として渡すことができるはず
検証
UnsafePointer
UnsafePointer - Swift Standard Library | Apple Developer Documentation
var n = 123 let np = UnsafeMutablePointer(&n) func show(_ p: UnsafePointer<Int>) { print(p.pointee) } show(np) // -> 123
UnsafeRawPointer
UnsafeRawPointer - Swift Standard Library | Apple Developer Documentation
let np = UnsafeMutableRawPointer.allocate(bytes: 4, alignedTo: 1) np.storeBytes(of: 0xFFFF_FFFF, as: UInt32.self) func show(_ p: UnsafeRawPointer) { print(p.load(as: UInt8.self)) } show(np) // -> 255
UnsafeBufferPointer
UnsafeBufferPointer - Swift Standard Library | Apple Developer Documentation
UnsafeMutableBufferPointer -> UnsafeBufferPointerは暗黙のアップキャストしない模様
型まで厳密に見てるという結果に
var n = 456 let np = UnsafeMutableBufferPointer(start: &n, count: 1) func showFirst<T>(_ p: UnsafeBufferPointer<T>) { if let p0 = p.first { print("\(p0)") } } showFirst(np) // -> error: cannot convert value of type 'UnsafeMutableBufferPointer<Int>' to expected argument type 'UnsafeBufferPointer<_>'
immutableなら想定通りに挙動
var n = 456 let np = UnsafeBufferPointer(start: &n, count: 1) func showFirst<T>(_ p: UnsafeBufferPointer<T>) { if let p0 = p.first { print("\(p0)") } } showFirst(np) // -> 456
UnsafeRawBufferPointer
UnsafeRawBufferPointer - Swift Standard Library | Apple Developer Documentation
UnsafeMutableRawBufferPointer -> UnsafeRawBufferPointerもUnsafeMutableBufferPointerと同じく、
暗黙のアップキャストは発生せず
var n = 256 let np = UnsafeMutableBufferPointer(start: &n, count: 1) let mnp = UnsafeMutableRawBufferPointer(np) func showFirst(_ p: UnsafeRawBufferPointer) { if let p0 = p.first { print("\(p0)") } } showFirst(mnp) // -> error: cannot convert value of type 'UnsafeMutableRawBufferPointer' to expected argument type 'UnsafeRawBufferPointer'
immutableなら想定通りは同一
var n = 256 let np = UnsafeMutableBufferPointer(start: &n, count: 1) let mnp = UnsafeRawBufferPointer(np) func showFirst(_ p: UnsafeRawBufferPointer) { if let p0 = p.first { print("\(p0)") } } showFirst(mnp) // -> 0
まとめ
つまり検証として暗黙的アップキャストが行われるのは
Mutable | Immutable | 暗黙的アップキャスト |
---|---|---|
UnsafeMutablePointer<T> | UnsafePointer<T> | OK |
UnsafeMutableRawPointer | UnsafeRawPointer | OK |
UnsafeMutableBufferPointer<T> | UnsafeBufferPointer<T> | NG |
UnsafeMutableRawBufferPointer | UnsafeRawBufferPointer | NG |