概要
- nimのポインタについて
- pointer, ptr, refとあるので調べてみた
検証
- pointer, ptr, refをそれぞれどんな時に使うのか
- pointer アドレスを扱う型
- ptr [型] [型]のアドレスを扱う型
- reprとかで値まで出力してくれる
- ref [型] [型]をnewするための型
みたいな考え方で良さそう
ref型はnewでメモリを確保するので、参照されなくなったら解放される。(GCされる)
アドレス自体をなんかしたい場合はptrとかpointerを使う。(この2つはGCされない)
pointerはどの型のポインタでも良く(Cで言うvoid*)、参照先を取りたい時は明示的にキャストしなければならない。
procの中で引数で渡した変数の値を変更したいときとかも、
var intとかして渡せば、out引数にできるので、わざわざポインタにして渡す必要とかはない。
example.nim
proc foo(num: var int) =
num = 100
foo(num)
echo num # 100
検証コード
example.nim
var
num: int = 300
num_ptr_1: ptr int = num.addr
num_ptr_2: pointer = num.addr
num_ref: ref int
echo repr(num_ptr_1)
echo repr(num_ptr_2)
echo repr(cast[ptr int](num_ptr_2))
proc ref_test(num: ref int) =
echo repr(num)
num_ref = new int
num_ref[] = 100
ref_test(num_ref)
出力
ref 0x10c40a1c8 --> 300
0x10c40a1c8
ref 0x10c40a1c8 --> 300
ref 0x10c4c8048 --> 100
オブジェクトのポインタの挙動
- type構文でref型を定義することができる
type
FooObj = object
num: int
Foo = ref FooObj
- let foo = new Foo などとするとfooはref Foo型になる(new時に確保したメモリの先頭アドレス)
type
FooObj = object
num: int
Foo = ref FooObj
let foo = new Foo
echo repr(foo)
出力
ref 0x106d17048 --> [num = 0]
- newしたオブジェクトを代入するとシャローコピー(ポインタになってるので当たり前ではある)
type
FooObj = object
num: int
Foo = ref FooObj
let foo = new Foo
echo repr(foo)
let fooPtr = foo
echo repr(fooPtr)
出力
ref 0x10062f048 --> [num = 0]
ref 0x10062f048 --> [num = 0]
- ref型をptrにしてみる
type
FooObj = object
num: int
Foo = ref FooObj
let foo = new Foo
echo repr(foo)
let fooPtr = foo
echo repr(fooPtr)
let fooPtrR: ptr FooObj = cast[ptr FooObj](new FooObj)
echo repr(fooPtrR)
出力
ref 0x103aca048 --> [num = 0]
ref 0x103aca048 --> [num = 0]
ref 0x103aca060 --> [num = 0]
- 使うタイミングがあるかは謎