রুবিতে অনেক আকর্ষণীয় অপারেটর রয়েছে।
যেমন:
- স্পেসশিপ অপারেটর (
<=>) - মডুলো অ্যাসাইনমেন্ট অপারেটর (
%=) - ট্রিপল ইক্যুয়ালস (
===) অপারেটর - বড় থেকে (
>) এবং ছোট থেকে (<) - নন-ইক্যুয়ালস (
!=)
আপনি যা বুঝতে পারেন না তা হল এই অপারেটরগুলির অনেকে আসলে রুবি মেথড।
এর মানে হলো...
আপনি তাদের কাজ ওভাররাইট করতে পারেন এবং আপনার নিজের ক্লাসে কাস্টম আচরণ সংজ্ঞায়িত করতে পারেন।
উদাহরণস্বরূপ, == সংজ্ঞায়িত করে আপনি রুবিকে বোঝাতে পারেন কীভাবে একই ক্লাসের দুটি অবজেক্ট তুলনা করবে।
এখন:
আসুন কিছু উদাহরণ দেখি যাতে আপনি এই রুবি অপারেটরগুলি কীভাবে কাজ করে এবং আপনার কোডে কীভাবে ব্যবহার করবেন সে সম্পর্কে একটি সুস্পষ্ট ধারণা পান।
যদি আপনি বাস্তবে রুবি বুঝতে চান তবে এটি একটি গুরুত্বপূর্ণ বিষয়।
রুবি লজিক্যাল অপারেটর
প্রথমে, আমরা লজিক্যাল অপারেটরগুলিকে দেখব।
আপনি এই অপারেটরগুলি ব্যবহার করতে পারেন দুটি অবজেক্ট তুলনা করতে এবং ফলাফলের উপর ভিত্তি করে সিদ্ধান্ত নিতে।
এখানে একটি টেবিল:
| অপারেটর | বিবরণ |
|---|---|
| < | ছোট থেকে |
| > | বড় থেকে |
| >= | বড় বা সমান |
| <= | ছোট বা সমান |
| == | সমান |
| != | নন-ইক্যুয়ালস |
| <=> | বড়, সমান, অথবা ছোট |
এই সব অপারেটরই মেথড, এবং তারা একটি বুলিয়ান মান ফেরত দেয়, স্পেসশিপ অপারেটর বাদে। স্পেসশিপ অপারেটর ১ (বড় থেকে), ০ (সমান) বা -১ (ছোট থেকে) ফেরত দেয়।
> অপারেটর ব্যবহার করার একটি উদাহরণ:
if orange.stock > 20 # ... end
যদি আপনি নিজের ক্লাসের সাথে ডাবল ইক্যুয়ালস (==) অপারেটর ব্যবহার করতে চান তবে আপনি দেখতে পাবেন এটি প্রথমে কাজ করে না...
উদাহরণ:
class Fruit
def initialize(name)
@name = name
end
end
orange1 = Fruit.new("orange")
orange2 = Fruit.new("orange")
orange1 == orange2 # false
এটির কারণ হল == এর ডিফল্ট ইমপ্লিমেন্টেশন BasicObject#==, যা object_id মেথড ব্যবহার করে দুটি অবজেক্ট একই কিনা তা নির্ধারণ করে।
আপনি এটিকে এভাবে ঠিক করতে পারেন:
class Fruit
attr_reader :name
def initialize(name)
@name = name
end
def ==(other)
name == other.name
end
end
এখানে আমরা বলছি দুটি ফল কখন একই:
তাদের নাম একই হতে হবে।
রুবি অ্যারিথমেটিক অপারেটর
পরবর্তী সেট হল অ্যারিথমেটিক অপারেটর।
এখানে কিছু নতুন নেই...
5 + 5 # 10 10 * 2 # 20 10 ** 2 # 100
কিন্তু == অপারেটরের মতোই, এগুলিও মেথড।
এটি কার্যকর কারণ আপনি সংজ্ঞায়িত করতে পারেন দুটি অবজেক্ট যোগ করলে কী হবে।
তাই যদি আপনার দুটি Order অবজেক্ট থাকে, সেগুলি যোগ করলে আপনাকে পেমেন্ট করার মোট পরিমাণ मिलবে, অথবা আপনি একটি নতুন অর্ডার পাবেন যা এই দুটি অর্ডারের সংমিশ্রণ।
আপনি + মেথড সংজ্ঞায়িত করে ঠিক কীভাবে কাজ করবে তা নির্ধারণ করতে পারেন।
আপনার পরিচিত নাও হতে পারে এমন একটি অপারেটর হলো মডুলো অপারেটর।
এটি পার্সেন্ট সাইন (%) এর মতো দেখায়।
এবং এটি করছে একটি ভাগশেষ দেয়।
উদাহরণ:
10 % 2 # 0
মডুলো অপারেটরের অনেক ব্যবহারিক ব্যবহার রয়েছে, যেমন কোনো সংখ্যা জোড় নাকি বিজোড় তা জানা, কোনো সংখ্যা অন্য সংখ্যা দিয়েও ভাগ যায় কিনা, কোনো সংখ্যার সীমা নির্ধারণ করা ইত্যাদি।
অ্যাসাইনমেন্ট অপারেটর (==, +=, ||=)
এখন আসি অ্যাসাইনমেন্ট অপারেটরে, এবং 이제 পর্যন্ত আমরা যা দেখেছি তার বিপরীতে, এগুলো মেথড নয়।
আপনার কাছে বেসিক অ্যাসাইনমেন্ট অপারেটর আছে:
a = 1
কিন্তু আপনার কাছে কম্বাইনড অ্যাসাইনমেন্ট অপারেটরও আছে:
a += 5 # 6 a *= 2 # 12
এইগুলো বর্তমান মান পড়ে, এর সাথে একটি অ্যারিথমেটিক অপারেটর ব্যবহার করে, তারপর ফলাফল সংরক্ষণ করার সমতুল্য। আপনি মডুলো অপারেটর (%) সহ সব অ্যারিথমেটিক অপারেটর দিয়ে এটি করতে পারেন।
কিন্তু দুটি অ্যাসাইনমেন্ট অপারেটর আছে যা ভিন্নভাবে আচরণ করে!
এই দুটি হল ||= এবং &&=।
এইগুলো ভিন্ন কারণ তারা সমতুল্য নয় অ্যারিথমেটিক ভার্সনের সাথে।
a ||= 100 যা করে তা হলো:
"যদি
aঅস্তিত্বে না থাকে অথবা যদি সেটিfalseবাnilহয় তবে100এসাইন করো, অন্যথায় শুধুaএর মান ফেরত দাও"
সাবसे নিকটতম সমতুল্য এক্সপ্রেশন যা আমি দিতে পারি:
(defined?(a) && a) ? a : a = 100
এটি উপকারী যদি আপনি কোনো ধীর গণনা বা API রিকোয়েস্টের ফলাফল সংরক্ষণ করতে চান, একটি প্রক্রিয়া যাকে "মেমোইজেশন" বলা হয়।
ইউনারি অপারেটর কী?
এখন পর্যন্ত আপনি শুধু দুটি ভ্যালুর সাথে কাজ করার অপারেটর দেখেছেন, কিন্তু এখানে শুধু একটি ভ্যালুর সাথে কাজ করার অপারেটরও আছে, আমরা এদের "ইউনারি অপারেটর" বলি।
উদাহরণস্বরূপ:
+"abc"
এটি একটি ফ্রোজেন স্ট্রিং-এর মিউটেবল কপি তৈরি করে।
আপনি নিজের ইউনারি অপারেটর (+ / -) সংজ্ঞায়িত করতে পারেন, কিন্তু আপনাকে কিছু বিশেষ সিনট্যাক্স ব্যবহার করতে হবে।
উদাহরণ:
class String
def +@
frozen? ? self.dup : self
end
end
str = "abc".freeze
p (+str).frozen? # false
আমাকে এখানে প্যারেনথেসিস ব্যবহার করতে হয়েছে ইউনারি অপারেটরগুলির প্রেসিডেন্সের কারণে।
আপনার কাছে !!ও আছে, যা একটি মেথড নয়:
!!123 # true !!nil # false
এটি উপকারী কারণ এটি যেকোনো মানকে বুলিয়ান হিসেবে রূপান্তর করবে।
তারপর আপনার কাছে ! আছে, যা একই কিন্তু বিপরীত বুলিয়ান মান দেয়।
উদাহরণ:
!true # false !!true # true !false # true
রুবি স্প্ল্যাট অপারেটর (উদাহরণসহ)
স্প্ল্যাট অপারেটর (*) আকর্ষণীয় কারণ এটি কিছু করে যা আপনি এর ছাড়া করতে পারবেন না।
মান लीজিয়ে আপনার কাছে একটি অ্যারে আছে:
attributes = [:title, :author, :category]
এবং আপনি এই অ্যারেটি একটি মেথডের সাথে ব্যবহার করতে চান যা ভেরিয়েবল আর্গুমেন্ট নেয়, যেমন attr_reader।
তাহলে আপনি এভাবে করতে পারেন:
attr_reader *attributes
স্প্ল্যাট অপারেটর অ্যারেটিকে তার উপাদানগুলির একটি তালিকায় রূপান্তর করে। যেন অ্যারেটি সরিয়ে তার ভেতরের সবকিছু রেখে দেওয়া হয়।
অন্য কথায়, উপরের উদাহরণটি এর সমতুল্য:
attr_reader :title, :author, :category
এটিই স্প্ল্যাট অপারেটরের শক্তি 🙂
ম্যাচিং অপারেটর (=~)
টিল্ডা সহ এই মজার রুবি অপারেটর (=~) কী?
এটি ম্যাচিং অপারেটর!
এটি আপনাকে রেগুলার এক্সপ্রেশন ব্যবহার করে দ্রুত ইনডেক্স সার্চ করতে দেয়।
এখানে একটি উদাহরণ:
"3oranges" =~ /[0-9]/ # 0
এটি সংখ্যা খোঁজে এবং স্ট্রিং-এ যেখানে প্রথম ম্যাচ পাওয়া যায় সে ইনডেক্স ফেরত দেয়, অন্যথায় নিল ফেরত দেয়।
অতিরিক্তভাবে, আপনার কাছে !~ অপারেটরও আছে, যা "নট ম্যাচ" অপারেটর।
উদাহরণ:
"abc" !~ /[0-9]/ # false
এখানে আপনি true বা false পাবেন, কোনো ইনডেক্স নয়, এটা মনে রাখবেন।
রুবি টার্নারি অপারেটর (প্রশ্নচিহ্ন অপারেটর)
যদি আপনি কম্প্যাক্ট এবং ছোট কোড পছন্দ করেন তবে আপনি রুবি টার্নারি অপারেটরকে ভালোবাসবেন।
এটি কম্প্যাক্ট if/else স্টেটমেন্ট লেখার একটি উপায়।
এটি এরকম দেখায়:
condition ? true : false
এখানে একটি উদাহরণ:
"".size == 0 ? "Empty string" : "Non-empty string"
এটি কীভাবে কাজ করে:
টার্নারি অপারেটরের প্রথম অংশ শর্ত নির্ধারণ করে ("".size == 0)।
তারপর একটি প্রশ্নচিহ্ন সিম্বল (?) থাকে।
তারপর, যখন শর্তটি সত্য হয় সেক্ষেত্রে ফেরত দেওয়ার মান থাকে।
তারপর একটি কোলন (:)।
এবং শেষ অংশ হলো যখন শর্তটি মিথ্যা হয় সেক্ষেত্রে ফেরত দেওয়ার মান, যা একটি পূর্ণ কন্ডিশনাল এক্সপ্রেশনে else হবে।
শভেল / পুশ অপারেটর (<<)
এই অপারেটর (<<)ও একটি মেথড, তাই আপনি কোন অবজেক্টের সাথে কাজ করছেন তার উপর নির্ভর করে এর আচরণ পরিবর্তিত হয়।
উদাহরণস্বরূপ, অ্যারেতে এটি শুধু push মেথডের একটি অ্যালিয়াস।
animals = [] animals << "cat"
স্ট্রিং-এ এটি শেষে অ্যাপেন্ড করবে:
"" << "cat"
এবং Integers-এর সাথে, এটি "লেফট শিফট" করবে, যা সকল বিট বাম দিকে ঘুরিয়ে দেয়।
2 << 1 # 4 2 << 2 # 8 2 << 3 # 16
ট্রিপল ইক্যুয়ালস অপারেটর (সadə সমানতা নয়)
আজ আমাদের শেষ অপারেটর হবে ট্রিপল ইক্যুয়ালস অপারেটর (===)।
এটিও একটি মেথড, এবং এটি এমন জায়গাও দেখানোর পাওয়া যায় যেখানও আপনি আশা করবেন না।
উদাহরণস্বরূপ, একটি কেস স্টেটমেন্টে:
case "bacon" when String puts "It's a string!" when Integer puts "It's an integer" end
রুবি এখানে ক্লাসের ওপর === মেথড কল করছে।
এভাবেঃ
String === "bacon"
এটি বর্তমান ক্লাসের সাথে অন্য অবজেক্টের ক্লাস তুলনা করে।
তাই এই অপারেটরটির উদ্দেশ্য হলো কেস স্টেটমেন্টের প্রসঙ্গে সমানতা সংজ্ঞায়িত করা।
সেইফ নেভিগেটর অপারেটর (&.)
আপনি কোনো অবজেক্টের ওপর একটি মেথড কল করতে চাইতে পারেন, কিন্তু সেই অবজেক্টটি nil হতে পারে, যা ভালো নয় কারণ nil এর ওপর মেথড কল করলে সাধারণত এরর হয়।
একটি সমাধান:
if user && user.active # ... end
এটি করার একটি ভালো উপায়:
if user&.active # ... end
এই &. হলো сейফ নেভিগেটর অপারেটর (রুবি ২.৩-এ চালু করা হয়েছে), যা user যদি nil না হয় তभी active মেথড কল করে।
খুবই উপকারী!
অপারেটর প্রেসিডেন্স টেবিল
রুবি আপনার সোর্স কোড একটি প্রায়োরিটি লিস্ট অনুসরণ করে ইভ্যালুয়েট করে, যেন গণিতে গুন এবং প্যারেনথেসিসের ক্ষেত্রে হয়।
যদি আপনি এটি কীভাবে কাজ করে না বুঝেন তবে এটি সব ধরনের এরর উৎপন্ন করতে পারে।
এখানে একটি টেবিল, উচ্চ থেকে নিম্ন প্রেসিডেন্স অনুযায়ী:
| অপারেটরগণ |
|---|
| !, ~, unary + |
| ** |
| unary - |
| *, /, % |
| +, - |
| <<, >> |
| & |
| |, ^ |
| >, >=, <, <= |
| <=>, ==, ===, !=, =~, !~ |
| && |
| || |
| ?, : |
| modifier-rescue |
| =, +=, -=, *=, /=, %= |
| defined? |
| not |
| or, and |
| modifier-if, modifier-unless, modifier-while, modifier-until |
| { } ব্লক |
| do ... end ব্লক |
Modifier-something বলতে এই কিওয়ার্ডগুলির এক-লাইন ভার্সন বোঝানো হয়।
উদাহরণ:
puts "awesome" if blog_name == "rubyguides"
এখানে একটি উদাহরণ যেখানে ব্লক প্রেসিডেন্স আপনাকে বিস্মিত করতে পারে:
# বড় হাতের অক্ষর সহ অ্যারে ফেরত দেয়
p ["a", "b", "c"].map { |character| character.upcase }
# Enumeraator অবজেক্ট ফেরত দেয়
p ["a", "b", "c"].map do |character|
character.upcase
end
প্রথম কেসে এটি প্রত্যাশা অনুযায়ী কাজ করে, দ্বিতীয় কেসে ব্লকের প্রেসিডেন্স কম থাকায় map মনে করে কোনো ব্লক নেই এবং একটি ইনামারেটর ফেরত দেয়।
সারসংক্ষেপ
আপনি রুবির অনেক অপারেটর সম্পর্কে জানতে পেরেছেন, অ্যারিথমেটিক অপারেটর থেকে লজিক এবং এমনকি সবচেয়ে অস্পষ্ট ইউনারি অপারেটর পর্যন্ত।
এই অপারেটরগুলির অনেকই আসলে মেথড যা আপনি আপনার নিজের ক্লাসে ইমপ্লিমেন্ট করতে পারেন।
আশা করি আপনি এটি উপকারী এবং আকর্ষণীয় পেয়েছেন!
পড়ার জন্য ধন্যবাদ 🙂