ট্র্যাক
/
Crystal
Crystal
/
সিলেবাস
/
প্রক ও ব্লক
প্

প্রক ও ব্লক মধ্যে Crystal

১টি অনুশীলনী

প্রক ও ব্লক সম্পর্কে

একটি ব্লক হলো কোডের একটি টুকরো যা একটি মেথডে পাস করা যায়। অন্য প্রোগ্রামিং ভাষায় এটিকে অ্যানোনিমাস ফাংশন বা ল্যাম্বডা বলা হয়। একটি মেথড একটি ব্লককে প্রস-এ রূপান্তর করতে পারে, যা কোডের একটি ব্লককে বোঝায়।

def my_method(&block)
  1 + yield
end

my_method { 2 }
# => 3

ব্লক আর প্রস Crystal-এ খুবই কমন, যেমন ইটারেশন ও কলব্যাকের কাজে। তবে DSL (ডোমেইন স্পেসিফিক ল্যাঙ্গুয়েজ) তৈরিতেও। DSL-এর কিছু উদাহরণ হলো ওয়েব ফ্রেমওয়ার্ক Kemal বা টেস্টিং ফ্রেমওয়ার্ক Spec (যেটি দিয়ে আপনার Crystal সলিউশনগুলো টেস্ট করা হয়)।

ব্লক

যে মেথড একটি ব্লক নিতে পারে, সেটি বানাতে হলে শেষ আর্গুমেন্টের আগে একটি অ্যাম্পারস্যান্ড (&) যোগ করতে হবে। এতে ব্লকটি একটি প্রস-এ রূপান্তরিত হবে এবং ওই আর্গুমেন্টে অ্যাসাইন হবে। এরপর yield ব্যবহার করলে মেথডকে দেওয়া ব্লকটি রান হবে।

def my_method(&block)
  1 + yield
end

ব্লক পাস করার দুটি উপায় আছে, হয় do ... end কিওয়ার্ড ব্যবহার করে, নয়তো কার্লি ব্রেস ({}) ব্যবহার করে। দুটির মধ্যে মূল পার্থক্য হলো প্রিসিডেন্স, do ... end মাল্টি-লাইন ব্লক সমর্থন করে, কিন্তু কার্লি ব্রেস ({}) করে না।

my_method do
  2
end
# => 3

my_method { 2 }
# => 3

Yield

yield হলো একটি কিওয়ার্ড যা মেথডকে দেওয়া ব্লকটি রান করে। এর মানে হলো, yield কল করা না হলে ব্লকটি কখনও রান হবে না। এটিকে আর্গুমেন্টও দেওয়া যায়, যেগুলো ব্লকে পাস করা হবে। ব্লকে যত খুশি আর্গুমেন্ট পাস করা যায়, এর কোনো সীমা নেই। ব্লকের ভেতরে আর্গুমেন্ট ব্যবহার করতে |x, y, ...| সিনট্যাক্স ব্যবহার করতে হয়। এখানে x, y, ... হলো আর্গুমেন্টগুলোর নাম।

def my_method(&block)
  1 + yield 2
end

# With curly braces:

my_method { |x| x * 3 }
# => 7

# With do ... end:

my_method do |x|
  x * 3
end
# => 7

উপরের উদাহরণে ব্লকটিকে আর্গুমেন্ট 2 দেওয়া হয়েছে, আর ব্লকটি এটিকে 3 দিয়ে গুণ করে 6 রিটার্ন করে। এরপর মেথডটি ফলাফলের সাথে 1 যোগ করে 7 রিটার্ন করে।

yield-কে দেওয়া আর্গুমেন্টের সংখ্যা ব্লকটি যত আর্গুমেন্ট আশা করে তার চেয়ে বেশি হলে একটি এরর রেইজ হবে।

def my_method(&block)
  1 + yield
end

my_method { |x| x * 3 }
# Error: too many block parameters (given 1, expected maximum 0)

ব্লকের ধরন

ব্লক এক্সপ্লিসিট বা ইমপ্লিসিটভাবে লেখা যায়। ইমপ্লিসিট ব্লকই সবচেয়ে কমন, আর উপরের উদাহরণগুলোতে সেগুলোই দেখানো হয়েছে। আপনি এমনকি ব্লককে ভিন্ন ভিন্ন টাইপের আর্গুমেন্টও দিতে পারেন, তখন কম্পাইলার টাইপগুলো ইনফার করে একটি ইউনিয়ন টাইপ তৈরি করবে।

def my_method(&block)
  yield "a"
  yield 1
end

my_method do |x|
  p typeof(x)
end

# output: (String | Int32)

এক্সপ্লিসিট ব্লক লেখার সময় আপনি আর্গুমেন্টগুলোর টাইপ এবং রিটার্ন টাইপ উল্লেখ করতে পারেন। এটি করা হয় Arg1Type, Arg2Type, ... -> ResultType সিনট্যাক্স দিয়ে। এখানে আর্গুমেন্টগুলো কমা (,) দিয়ে এবং রেজাল্ট টাইপ -> দিয়ে আলাদা করা হয়।

def my_method(&block : Int32, Int32 -> Int32)
  1 + yield(2, 3)
end

my_method { |x, y| x * y }
# => 7

অন্য এক্সপ্লিসিট টাইপের মতো এখানেও কম্পাইলার নিশ্চিত করে যে টাইপগুলো প্রত্যাশিত অনুযায়ীই আছে। ব্লকটি মেথডে দেওয়া টাইপের সাথে না মিললে একটি এরর রেইজ হবে।

শর্টহ্যান্ড

যে ব্লকগুলো কেবল একটি আর্গুমেন্ট নেয় এবং তার উপর কেবল একটি মেথড কল করে, তাদের জন্য একটি শর্টহ্যান্ড আছে। |x| ব্যবহার না করে আপনি আর্গুমেন্টের নামের আগে & ব্যবহার করতে পারেন।

def my_method(&block)
  yield "a"
end

# This is: 

my_method { |x| x.upcase }
# => "A"

# Is the same as:

my_method &.upcase
# => "A"

প্রস

Proc-এর ব্লকের সাথে খুব গভীর সম্পর্ক আছে। মূল পার্থক্য হলো, Proc একটি টাইপ, আর ব্লক নয়। একটি Proc একটি ফাংশন পয়েন্টারকে বোঝায় এবং ভ্যারিয়েবল হিসেবে এদিক-ওদিক পাস করা যায়।

একটি Proc ডিফাইন করতে আপনি প্রস লিটারাল ->(args) { ... } সিনট্যাক্স ব্যবহার করেন। আর্গুমেন্টগুলো কমা (,) দিয়ে এবং ব্লকটি { ... } দিয়ে আলাদা করা হয়। একটি প্রস ইনভোক করতে আপনি call মেথড ব্যবহার করেন এবং সেটিতে আর্গুমেন্টগুলো পাস করেন। প্যারামিটারগুলোর টাইপ বাধ্যতামূলক। রিটার্ন টাইপ প্রসের বডি থেকে ইনফার করা হয়, তবে এক্সপ্লিসিটভাবেও দেওয়া যায়।

my_proc = ->(x : Int32, y : Int32) : Int32 { x * y }
my_proc.call(2, 3)
# => 6

ব্লক ক্যাপচার করা

ব্লক ক্যাপচার করা হলো একটি ব্লক থেকে Proc তৈরির একটি উপায়। এটি করা হয় মেথডের শেষ আর্গুমেন্টের আগে & অপারেটর ব্যবহার করে। এতে ব্লকটি একটি Proc-এ রূপান্তরিত হবে এবং ওই আর্গুমেন্টে অ্যাসাইন হবে।

def my_method(&block)
  block.call
end

my_method { 1 + 2 }
# => 3

মেথডে প্রস পাস করা

যে মেথডগুলো একটি ব্লক আশা করে, সেগুলোতে প্রস পাস করা যায়। কোনো শর্তের ভিত্তিতে ভিন্ন ভিন্ন ব্লক পাস করতে চাইলে এটি কাজে লাগে।

def my_method(&block)
  yield 5
end

my_proc = -> (x) { x * 2 }
my_method(&my_proc)
# => 10

ভ্যারিয়েবলের টাইপ ডিক্লেয়ার করা

ভ্যারিয়েবল ডিক্লেয়ার করার সময় আপনি ভ্যারিয়েবলটির টাইপ ডিক্লেয়ার করতে : Type সিনট্যাক্স ব্যবহার করতে পারেন। প্রসের ক্ষেত্রে আপনি Proc((ArgType, ...), ResultType) সিনট্যাক্স ব্যবহার করেন। শেষ টাইপটি সবসময় রিটার্ন টাইপ হবে, আর বাকিগুলো আর্গুমেন্টের টাইপ হবে। অর্থাৎ, যদি কেবল একটি টাইপ থাকে, তাহলে সেটিই রিটার্ন টাইপ হবে এবং প্রসটি কোনো আর্গুমেন্ট নেবে না।

my_proc : Proc(Int32, Int32, Int32) = ->(x, y) { x * y }
other_proc : Proc(Int32) = -> { 1 }

মেথড থেকে প্রস ডিক্লেয়ার করা

আপনি একটি মেথড থেকে প্রসও ডিক্লেয়ার করতে পারেন।

def my_method(a, b)
  a + b
end

my_proc = ->my_method(Int32, Int32)
my_proc.call(2, 3)
GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি নতুন একটি উইন্ডো বা ট্যাবে খুলবে

প্রক ও ব্লক শিখুন

অনুশীলন লক করা আছে

প্রক ও ব্লক অনুশীলন করতে আরও ১টি অনুশীলনী আনলক করুন