Подтвердить что ты не робот

Какова модель стоимости по сравнению с ссылкой в ​​Nimrod?

ПРИМЕЧАНИЕ: Я не спрашиваю о различии между указателем и ссылкой, и для этого вопроса это совершенно не имеет значения.

Одна вещь, которую я не мог найти в явном виде: какая модель использует Нимрод?

Как и С++ - где у вас есть значения и с new вы создаете указатели на данные (в таком случае переменная может содержать указатель на указатель на указатель на... для данных)?

Или как С# - где у вас есть типы POD как значения, но определенные пользователем объекты с ссылкой (неявно)?

Я заметил, что разыменование происходит автоматически, как в Go.

Перефразировать. Вы определяете свой новый тип, скажем Student (с именем, университетом, адресом). Вы пишете:

var student ...?
  • сделать Student текущие данные (Student type/class)
  • сделать Student удержание указателя на данные
  • сделать Student удержание указателя на указатель на данные

Или некоторые из этих точек невозможны?

4b9b3361

Ответ 1

По умолчанию модель предназначена для передачи данных по значению. Когда вы создаете var определенного типа, компилятор будет выделять в стеке необходимое пространство для переменной. Что ожидается, поскольку Nim компилируется на C, а сложные типы - это просто структуры. Но, как и на C или С++, вы можете иметь указатели. Существует ключевое слово ptr, чтобы получить небезопасный указатель, в основном для взаимодействия с кодом C, и есть ref, чтобы получить безопасную ссылку на сборщик мусора (оба задокументированы в Ссылки и типы указателей в руководстве Nim).

Однако обратите внимание, что даже если вы укажете proc для передачи переменной по значению, компилятор может решить передать его по ссылке, если он считает, что он может ускорить выполнение и одновременно безопасен. На практике единственный раз, когда я использовал ссылки, когда я экспортировал типы 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, указанную ниже, чтобы вы могли вернуть bool с указанием успеха. Отказ обычно обрабатывается по-разному.
  • В C-подобных языках theres является явным синтаксисом для доступа к значению памяти указателя или значениям памяти, указанным им (разыменование). В Nim также есть, и это пустое обозначение индекса ([]). Однако компилятор попытается автоматически поместить их во избежание загромождения кода. Следовательно, пример не использует их. Чтобы доказать это, вы можете изменить код следующим образом:

    echo b[].name & " " & $b[].age

    Что будет работать и компилироваться, как ожидалось. Но следующее изменение приведет к ошибке компилятора, потому что вы не можете разыменовать не ссылочный тип:

    echo a[].name & " " & $a[].age

  • Текущая тенденция в сообществе Nim заключается в избавиться от однобуквенных префиксов, чтобы различать значения по сравнению с ссылочными типами. В старой конвенции вы должны иметь TPerson и псевдоним для ссылочного значения как PPerson = ref TPerson. Вы можете найти много кода, все еще используя это соглашение.

  • В зависимости от того, что именно должен делать ваш объект и конструктор, вместо того, чтобы initPerson вернуть значение, вы также можете иметь init(x: var Person, ...). Но использование неявной переменной result позволяет компилятору оптимизировать это, так что это гораздо более предпочтительный вкус или требования передачи bool вызывающему.

Ответ 2

Это может быть.

type Student = object ...

примерно эквивалентен

typedef struct { ... } Student;

в C, а

type Student = ref object ...

или

type Student = ptr object ...

примерно эквивалентен

typedef struct { ... } *Student;

в C (с ref, обозначающим ссылку, которая отслеживается сборщиком мусора, а ptr не прослеживается).