知らなかったので、メモしておきます。
Swiftでポインタを使う?
とある本を読んでたら、
「変数名の前に&をつけることで、その変数のためにメモリ上で確保された領域の開始位置が取得できます」
と書いてありました。
C言語じゃあるまいし、そんなことできんの? と思って調べてみたら、できるようになってました。
Swiftの設計思想的にどうなの?
Swiftの言語設計として、「静的型付け言語である」という点があげられます。
これにより、コンパイル時に変数の型は保証されており、
変数の型が合わないことによるエラーはコンパイラが発見できるので、安心! 嬉しい! というわけなのですが、
ポインタを使うと、正直なんでもできちゃうから危なくね? と思ったわけです。
実際言語として、プログラマーに低レイヤの処理を一切やらせない設計にすることも可能だとは思うんですが、
それをやってしまうと、ホントにメモリ上を操作しないといけないような処理ができず、言語の制約になってしまいます。
そこでUnsafePointer<T>
Swiftはそれを解決するために、UnsafePointer<T>という型を用意しています。
「Unsafe」と書いてあるので、未熟なプログラマーでもひと目で「こいつは危ない!」とわかりますね。
低レイヤの話なので、文章だとちょっと難しいですが、
UnsafeMutablePointerの説明にあったサンプルコードが直感的でした。
var bytes: [UInt8] = [39, 77, 111, 111, 102, 33, 39, 0]
let uint8Pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: 8)
uint8Pointer.initialize(from: &bytes, count: 8)
たった3行のコードで、&を使ったポインタの使用例が説明できます。
やってることは、配列の先頭を指定したUnsafeMutablePointerオブジェクトを作っているだけです。
bytesという8Byte符号なしInt型の配列があります。
これは何の変哲もない配列です。
2行目は、UnsafeMutablePointerオブジェクトを生成しています。
この時点ではこのオブジェクトはinitializeおらず、どこのアドレスも指していません。
これをinitializeしているのが、3行目です。
関数定義はこんなん。
func initialize(from source: UnsafePointer<Pointee>, count: Int)
引数のfromで、UnsafePointerを指定します。
MutableがついていないUnsafePointer型です。
countは要素数を入れます。
これで配列のアドレスを好き勝手指定できるポインタが生成できました! おめでとう!
ユースケース
サンプルコードだと、普通に配列のsubscript使っても同じことできます。
あくまでサンプルはポインタの生成をわかりやすく説明するためのコードなので、実用性はなさそうです。
実際ポインタを使うのは、Objective-Cからのコード移植とか、
あと画像の色要素を細かくいじるときとか、ユースケースは限られるとは思います。
僕が今回出会ったのは色要素を指定する処理でした。
もっと詳しく
素晴らしいSwiftのポインタ型の解説
このあたりがいいかと。