особенности ООП - ponyatov/nimbook GitHub Wiki
особенности ООП
- в Nim нет инкапсуляции:
- определение типа (класса) и процедуры (метода) описываются отдельно, и могут находится в полностью независимых модулях
- любая процедура автоматически является методом для типа ёё первого аргумента
- в своём коде вы можете абсолютно свободно (пере)определять методы для любых типов из сторонних библиотек
Определение объекта в Nim полностью эквивалентно структуре в языке Си, и именно так передается в C-код через FFI. Новые типы определяются синтаксической конструкцией type
. Определение объекта может быть помещено в одной строке с ключевым словом type
или в виде блока под ним:
type
Person = object
name: string
age: int
В type
-блоке могут определяться несколько типов, и именно так желательно собирать связанные типы (структура кода очень похожа на Паскаль). Как и процедуры, типы должны быть сначала определены над кодом, в котором они используются.
Переменная, использующая тип Person
, объявляется так же, как и любая другая переменная:
var person: Person
Типы принято именовать с большой буквы, инстансы (переменные) с маленькой (как в Smalltalk).
Использовать неинициализированные переменные считается очень плохим стилем, поэтому при возможности объявляйте инициализированные переменные:
var person = Person(name: "Neo", age: 28)
Вы можете указать все, некоторые или ни одно из полей. Для object
-типов память размещается в стеке. Освобождение памяти для них самое простое -- удаляется все, что выходит за границы текущего вызова процедуры.
Когда вы определяете новую переменную, вы не можете изменить где для неё распределяется память -- в стеке или в куче. Если вы хотите выделять переменные в куче, нужно изменить само определение типа: ref object
объекты распределяются в куче. Наличие ref
намекает на использования подсчета ссылок для определения тех объектов, которые могут быть удалены из памяти, так как не используются в других объектах. Объекты с циклическими ссылками дочищает сборщик мусора.
Типы, определенные с помощью ключевого слова ref
, называются ссылочными типами. Когда экземпляр ссылочного типа передается в качестве параметра в процедуру, вместо передачи копии объекта по значению, он передается по ссылке. Это позволяет вам изменять исходный объект, соответствующий переданному параметру процедуры, как изнутри вашей процедуры, так и снаружи (в т.ч. асинхронно). non-ref объекты, передаваемые в качестве параметра в процедуру, являются неизменяемыми, так как все операции выполняются с копией объекта на стеке, и будут выброшены при выходе из процедуры вместе с освобождением памяти этой копии.
Если требуется работать сразу с ref и non-ref вариантами, предлагается следующий паттерн с наследованием:
type
PersonObj = object
name: string
age: int
PersonRef = ref PersonObj
по соглашениям для non-ref используется суффикс типа Obj
и от него наследуюется ссылочный тип с суффиксом Ref
.
Для обращения к полям ref-объектов никакой специальный синтаксис не требуется:
proc setName(person: PersonObj) =
let x = person.name
# ошибка: модификация иммутабельного нессылочного параметра
# nim compiler Error: 'person.name' cannot be assigned to
person.name = "George"
proc setName(person: PersonRef) =
person.name = "George"