Ответ 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
вызывающему.