«گترها» و «سترها» متدهایی هستند که به شما امکان میدهند مقدار یک ویژگی از شیء را بخوانید و بنویسید. Crystal ماکرو دارد و همین کار تعریف گتر و ستر برای یک ویژگی را آسان میکند. «ماکرو» روشی برای تولید کد در زمان کامپایل است که بعداً در مفهوم ماکرو به آن پرداخته میشود.
در Ruby این متدها با استفاده از متدهای attr_reader، attr_writer و attr_accessor تعریف میشوند و در ظاهر بسیار شبیه پیادهسازی Crystal هستند.
Crystal اینها را بهصورت ماکروهای getter، setter و property تعریف کرده است.
گتر ماکرویی است که متدی تعریف میکند که مقدار یک متغیر نمونه را برمیگرداند.
این یعنی دیگر لازم نیست وقتی میخواهید به یک متغیر نمونه دسترسی داشته باشید، @ را جلوی آن بنویسید (در متدها، بهجز initialize)؛ در عوض میتوانید متدی را که ماکروی گتر تعریف کرده است فراخوانی کنید.
ماکروی گتر میتواند چند متغیر نمونه را بپذیرد، به شرط اینکه آنها را با کاما از هم جدا کنید.
# 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
همانطور که میبینید، استفاده از گتر مقدار کدی که مینویسید را کاهش میدهد و خواندن آن را آسانتر میکند. همچنین Ruby و Crystal در این نکته با هم تفاوت دارند که Crystal هم اسم متغیر و هم نماد را بهعنوان آرگومان برای ماکروی گتر میپذیرد. نمادها بعداً در مفهوم نماد بررسی میشوند.
ستر ماکرویی است که متدی تعریف میکند که مقدار یک متغیر نمونه را تنظیم میکند.
این ماکرو چندان رایج نیست و معمولاً بهجای آن از ماکروی property استفاده میشود.
متدهایی که ساخته میشوند به شکل name_of_method= خواهند بود؛ همین = است که امکان تنظیم ویژگی را فراهم میکند.
این تعریف متد کمی خاص است، چون آرگومانی که متد دریافت میکند بعد از علامت = میآید.
چند متد خاص دیگر هم در Crystal از این نحوهی نگارش استفاده میکنند، مثل متد +.
مانند ماکروی گتر، وقتی بعد از تعریف یک ستر میخواهید مقدار یک متغیر نمونه را بهروزرسانی کنید، میتوانید متدی را که ماکروی ستر تعریف کرده است فراخوانی کنید.
# 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
پراپرتی ماکرویی است که هم گتر و هم ستر را برای یک متغیر نمونه تعریف میکند.
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= را پیادهسازی کنید تا بتوان واحد را تنظیم کرد.
این ویژگی باید یک مقدار «منطقی» بپذیرد.
precision = 3
metric = true
wm = WeighingMachine.new(precision, metric)
vm.weight = 60.5
wm.metric = false
vm.weigh
# => 133.377