27

注:ポインターと参照の違いについて質問しているわけではありません。この質問では、まったく関係ありません。

明示的に述べられていないことが 1 つあります。Nim はどのモデルを使用していますか?

C++ のように -- 値があり、newデータへのポインタを作成する場所 (このような場合、変数はポインタへのポインタへのポインタを保持できます... データへのポインタ)?

または、C# のように、値として POD 型を持っていますが、(暗黙的に) 参照されるユーザー定義オブジェクトがありますか?

Goのように、逆参照のみが自動であることがわかりました。

言い換えます。Studentたとえば、新しいタイプを(名前、大学、住所で)定義します。あなたが書く:

var student ...?
  1. (型/クラスの)student実際のデータを保持するStudent
  2. studentデータへのポインタを保持する
  3. studentデータへのポインタへのポインタを保持する

それともそれらの点からいくつかは不可能ですか?

4

2 に答える 2

35

デフォルトでは、データを値渡しするモデルです。特定の型の var を作成すると、コンパイラは変数に必要なスペースをスタックに割り当てます。Nim は C にコンパイルされ、複雑な型は単なる構造であるため、これは当然のことです。ただし、C や C++ と同様に、ポインターも使用できます。ptr主に C コードとのインターフェイス用に、アンセーフ ポインターを取得するキーワードとref、ガベージ コレクトされた安全な参照を取得するキーワードがあります (どちらも Nim マニュアルの「参照とポインター型」セクションに記載されています)

ただし、proc変数を値渡しするように a を指定した場合でも、実行速度が向上し、同時に安全であるとコンパイラが判断した場合、コンパイラは変数を参照渡しで内部的に渡すことを自由に決定できることに注意してください。実際に参照を使用したのは、Nim 型を C にエクスポートし、C と Nim の両方が同じメモリを指していることを確認する必要があったときだけです。生成された C コードはいつでもnimcacheディレクトリで確認できることに注意してください。varproc 内のパラメーターは、その 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 コミュニティの現在の傾向は、値と参照型を区別するために単一文字のプレフィックスを取り除くことです。古い慣例では、 と参照値のエイリアスを として持っていましTPersonPPerson = ref TPerson。この規則を使用している多くのコードを見つけることができます。

  • オブジェクトとコンストラクターが正確に何をする必要があるかに応じてinitPerson、値を返す代わりにinit(x: var Person, ...). しかし、暗黙の変数を使用すると、コンパイラはこれを最適化できます。そのため、呼び出し元にresulta を渡す際の好みや要件がより重要になります。bool
于 2014-02-28T15:40:10.217 に答える
6

どちらでもかまいません。

type Student = object ...

とほぼ同等です

typedef struct { ... } Student;

Cでは、

type Student = ref object ...

また

type Student = ptr object ...

とほぼ同等です

typedef struct { ... } *Student;

C で (refガベージ コレクターによってトレースされる参照を示しますが、トレースされptrません)。

于 2014-02-28T16:19:31.317 に答える