Гетери та сетери - це методи, які дозволяють читати й записувати значення властивості обʼєкта. У Crystal є макроси, завдяки яким легко визначати гетери та сетери для властивості. Макроси - це спосіб генерувати код під час компіляції, про що йтиметься пізніше в концепції макросів.
У Ruby ці методи визначають за допомогою методів attr_reader, attr_writer та attr_accessor, і зовні вони дуже схожі на реалізацію в Crystal.
У Crystal їх визначено як макроси getter, setter і property.
getter - це макрос, який визначає метод, що повертає значення змінної екземпляра.
Це означає, що більше не потрібно писати @ перед змінною екземпляра, коли ми хочемо отримати до неї доступ (у методах, крім initialize); натомість можна викликати метод, який визначив макрос getter.
Макрос getter може приймати кілька змінних екземпляра, розділених комами.
# This:
class Person
@name : String
@age : Int32
def name
@name
end
def age
@age
end
end
# Is the same as this:
class Person
@name : String
@age : Int32
getter name, :age
end
Як бачимо, використання getter зменшує обсяг коду, який ми пишемо, і робить його легшим для читання.
Крім того, Ruby та Crystal відрізняються тим, що Crystal приймає і назву змінної, і symbol як аргументи для макросу getter.
Символи буде розглянуто пізніше в концепції symbol.
setter - це макрос, який визначає метод, що встановлює значення змінної екземпляра.
Цей макрос трапляється нечасто, і зазвичай замість нього використовують макрос property.
Методи, які буде створено, матимуть вигляд name_of_method=; саме = робить так, що властивість можна встановити.
Це визначення методу трохи особливе, бо аргумент, який отримує метод, стоїть після знака =.
Кілька інших особливих методів у Crystal використовують цей синтаксис, наприклад метод +.
Як і з макросом getter, коли ми хочемо оновити значення змінної екземпляра після визначення setter, можна викликати метод, який визначив макрос setter.
# This:
class Person
@name : String
@age : Int32
def name=(name : String)
@name = name
end
def age=(age : Int32)
@age = age
end
end
# Is the same as this:
class Person
@name : String
@age : Int32
setter name, :age
end
propertyproperty - це макрос, який визначає і гетер, і сетер для змінної екземпляра.
class Person
@name : String
@age : Int32
property name, :age
end
У цій вправі ми змоделюємо машину для зважування.
Під час ініціалізації машина для зважування має орієнтуватися на заводські налаштування, які відрізняються залежно від того, де цю машину продають. Тож машину має бути можливо ініціалізувати із заданою точністю та вказівкою, чи використовувати метричну систему, чи імперську.
Реалізуйте метод WeighingMachine#initialize, який приймає два аргументи: precision типу Int32 і metric типу Bool.
Аргумент metric зі значенням true означає, що машина має використовувати метричну систему, інакше вона має використовувати імперську.
Метод initialize також має встановити значення змінної екземпляра @weight рівним 0.0.
precision = 3
metric = true
vm = WeighingMachine.new(precision, metric)
Щоб задовольнити різні потреби, кожну машину для зважування можна налаштувати з певною точністю (кількістю цифр після десяткового розділювача).
Реалізуйте метод-гетер WeighingMachine#precision, який повертає точність машини для зважування.
precision = 3
metric = true
vm = WeighingMachine.new(precision, metric)
vm.precision
# => 3
Реалізуйте властивість WeighingMachine#weight, щоб вагу можна було і читати, і встановлювати:
precision = 3
metric = true
wm = WeighingMachine.new(precision, metric)
wm.weight = 60.5
wm.weight
# => 60.5
wm.weigh
# => 60.5
Реалізуйте властивість WeighingMachine#metric=, щоб можна було змінювати одиниці вимірювання.
Вона має приймати булеве значення (англ. Boolean).
precision = 3
metric = true
wm = WeighingMachine.new(precision, metric)
vm.weight = 60.5
wm.metric = false
vm.weigh
# => 133.377
Зареєструйтеся на Exercism, щоб вивчати й опановувати Crystal, а також 26 концепцій142 вправи та справжнє наставництво від людей, і все це безкоштовно.