デフォルトでは、データを値渡しするモデルです。特定の型の var を作成すると、コンパイラは変数に必要なスペースをスタックに割り当てます。Nim は C にコンパイルされ、複雑な型は単なる構造であるため、これは当然のことです。ただし、C や C++ と同様に、ポインターも使用できます。ptr
主に C コードとのインターフェイス用に、アンセーフ ポインターを取得するキーワードとref
、ガベージ コレクトされた安全な参照を取得するキーワードがあります (どちらも Nim マニュアルの「参照とポインター型」セクションに記載されています) 。
ただし、proc
変数を値渡しするように a を指定した場合でも、実行速度が向上し、同時に安全であるとコンパイラが判断した場合、コンパイラは変数を参照渡しで内部的に渡すことを自由に決定できることに注意してください。実際に参照を使用したのは、Nim 型を C にエクスポートし、C と Nim の両方が同じメモリを指していることを確認する必要があったときだけです。生成された C コードはいつでもnimcache
ディレクトリで確認できることに注意してください。var
proc 内のパラメーターは、その C 構造体への単なるポインターであることがわかります。
以下は、スタック上に作成され、値によって渡されるコンストラクターと、バージョンのような対応するポインターを含む型の例です。
type
Person = object
age: int
name: string
proc initPerson(age: int, name: string): Person =
result.age = age
result.name = name
proc newPerson(age: int, name: string): ref Person =
new(result)
result.age = age
result.name = name
when isMainModule:
var
a = initPerson(3, "foo")
b = newPerson(4, "bar")
echo a.name & " " & $a.age
echo b.name & " " & $b.age
ご覧のとおり、コードは基本的に同じですが、いくつかの違いがあります。
- 初期化を区別する一般的な方法は、値型にはinitを使用し、参照型にはnewを使用することです。また、Nim 独自の標準ライブラリは、この規則よりも古いコードがあるため、この規則を誤っていることに注意してください (たとえば、newStringOfCap は文字列型への参照を返さない)。
- コンストラクターが実際に何をするかに応じて、
ref
バージョンでは値を返すことができますnil
が、これはエラーとして扱うことができますが、値コンストラクターでは例外を発生させるか、コンストラクターを変更して下記のvar 形式を使用するように強制するため、値を返すことができます。成功を示すブール値。失敗はさまざまな方法で扱われる傾向があります。
C に似た言語では、ポインターのメモリー値またはポインターが指すメモリー値にアクセスするための明示的な構文があります (逆参照)。Nim にもあり、それは空の添字表記 ( []
) です。ただし、コンパイラは、コードが乱雑になるのを避けるために、それらを自動的に配置しようとします。したがって、この例ではそれらを使用していません。これを証明するために、コードを次のように変更できます。
echo b[].name & " " & $b[].age
これは期待どおりに動作し、コンパイルされます。ただし、次の変更では、非参照型を逆参照できないため、コンパイラ エラーが発生します。
echo a[].name & " " & $a[].age
Nim コミュニティの現在の傾向は、値と参照型を区別するために単一文字のプレフィックスを取り除くことです。古い慣例では、 と参照値のエイリアスを として持っていましTPerson
たPPerson = ref TPerson
。この規則を使用している多くのコードを見つけることができます。
- オブジェクトとコンストラクターが正確に何をする必要があるかに応じて
initPerson
、値を返す代わりにinit(x: var Person, ...)
. しかし、暗黙の変数を使用すると、コンパイラはこれを最適化できます。そのため、呼び出し元にresult
a を渡す際の好みや要件がより重要になります。bool