কম্পিউটার

#to_s বা #to_str? রুবিতে স্পষ্টভাবে কাস্টিং বনাম অন্তর্নিহিতভাবে জোর করা প্রকার

টাইপ জবরদস্তি হল একটি বস্তুর প্রকারকে অন্য প্রকারে পরিবর্তন করা, এর মান সহ। উদাহরণস্বরূপ, #to_s দিয়ে একটি পূর্ণসংখ্যাকে একটি স্ট্রিংয়ে পরিবর্তন করুন অথবা #to_i দিয়ে একটি পূর্ণসংখ্যার মধ্যে ফ্লোট করুন . সম্ভবত কম পরিচিত #to_str এবং #to_int পদ্ধতি কিছু বস্তু প্রয়োগ করে প্রথম নজরে একই কাজ করে, কিন্তু কিছু পার্থক্য আছে।

AppSignal একাডেমীর এই সংস্করণে, আমরা রুবিতে স্পষ্টভাবে কাস্টিং এবং অন্তর্নিহিতভাবে জোর করার ধরনগুলিতে ডুব দেব, টাইপকাস্টিং অভিনেতাদের সংক্ষিপ্তভাবে স্পর্শ করার সময়। আমরা উভয় পদ্ধতির মধ্যে পার্থক্যগুলি কভার করব এবং সেগুলি কীভাবে ব্যবহার করা হয় তা নিয়ে আলোচনা করব৷

আসুন প্রথমে দেখি কিভাবে আমরা রুবিতে স্পষ্ট কাস্টিং সহায়ক সহ বিভিন্ন ধরণের মানকে জোর করে দেই৷

স্পষ্ট কাস্টিং সাহায্যকারী

সবচেয়ে সাধারণ কাস্টিং সহায়ক হল #to_s , #to_i , #to_a এবং #to_h . এগুলি হল সুস্পষ্ট ঢালাই পদ্ধতি৷ তারা আমাদের সহজেই একটি মানকে এক প্রকার থেকে অন্য প্রকারে রূপান্তর করতে সহায়তা করে৷

সুস্পষ্ট সাহায্যকারীরা একটি স্পষ্ট প্রতিশ্রুতি নিয়ে আসে। যখনই #to_s একটি বস্তুর উপর বলা হয়, এটি সর্বদা হবে একটি স্ট্রিং ফেরত দিন, এমনকি যদি বস্তুটি সত্যিই একটি স্ট্রিং-এ রূপান্তরিত না হয়। এটি ব্যাটম্যান হিসাবে মাইকেল কিটনকে কাস্ট করার মতো। আপনি একজন ব্যাটম্যান পাবেন, এমনকি যদি একজন কমেডি অভিনেতা এই চরিত্রের জন্য বিশেষভাবে উপযুক্ত না হয়।

রুবি রুবি স্ট্যান্ডার্ড লাইব্রেরিতে প্রায় যেকোনো মৌলিক বস্তুতে এই সহায়ক পদ্ধতিগুলি অফার করে৷

:foo.to_s # => "foo"
10.0.to_i # => 10
"10".to_i # => 10

এই পদ্ধতিগুলি, বিশেষ করে #to_s , রুবিতে বেশিরভাগ মৌলিক প্রকারের উপর প্রয়োগ করা হয়। যদিও কাস্টিং প্রায় সবসময় একটি মান প্রদান করে, ফলাফল আমরা যা আশা করি তা নাও হতে পারে।

"foo10".to_i          # => 0
[1, 2, 3].to_s        # => "[1, 2, 3]"
{ :foo => :bar }.to_s # => "{:foo=>:bar}"
{ :foo => :bar }.to_a # => [[:foo, :bar]]
Object.to_s           # => "Object"
Object.new.to_s       # => "#<Object:0x00007f8e6d053a90>"

#to_s কল করা হচ্ছে , #to_i , #to_a এবং #to_h হেল্পাররা যে কোন মানকে নির্বাচিত প্রকারের সাথে জোর করে। মানের সাথে যা ঘটবে তা নির্বিশেষে তারা যে ধরনের একটি প্রতিনিধিত্ব করে তা জোরপূর্বক প্রদান করে।

অন্তর্নিহিত জবরদস্তি পদ্ধতি

আমরা যে ধরনের কাস্টিং করছি তার মতো কাজ করে না এমন মানগুলির উপর টাইপ কাস্টিং পদ্ধতি কল করার ফলে ত্রুটি বা ডেটার ক্ষতি হতে পারে। রুবি অন্তর্নিহিত জবরদস্তি পদ্ধতিও অফার করে যা শুধুমাত্র একটি মান ফেরত দেয় যখন বস্তু টাইপের মত কাজ করে। এইভাবে আমরা নিশ্চিত হতে পারি যে মানটি আমাদের পছন্দ মতো কাজ করে। এই অন্তর্নিহিত জবরদস্তি পদ্ধতি হল #to_str , #to_int , #to_ary এবং #to_hash .

অন্তর্নিহিত জবরদস্তি হল লিওনার্ড নিময়কে স্পক ছাড়া যে কোনো ভূমিকায় কাস্ট করার মতো। যদি চরিত্রটি স্পকের যথেষ্ট কাছাকাছি হয় তবে তারা কাজ করবে, কিন্তু যদি না হয় তবে ব্যর্থ হয়। #to_str সাহায্যকারী চেষ্টা করে একটি স্ট্রিং এ রূপান্তর করতে, কিন্তু একটি NoMethodError উত্থাপন করবে যদি বস্তুটি পদ্ধতিটি বাস্তবায়ন না করে এবং পরোক্ষভাবে জোর করা যায় না।

10.to_int                           # => 10
10.0.to_int                         # => 10
require "bigdecimal"
BigDecimal.new("10.0000123").to_int # => 10
 
# Unsuccessful coercions
"10".to_int             # => NoMethodError
"foo10".to_int          # => NoMethodError
[1, 2, 3].to_str        # => NoMethodError
{ :foo => :bar }.to_str # => NoMethodError
{ :foo => :bar }.to_ary # => NoMethodError
Object.to_str           # => NoMethodError
Object.new.to_str       # => NoMethodError

আমরা দেখতে পাচ্ছি যে রুবি এখন যা করে তাতে একটু বেশি কঠোর এবং অনুরোধ করা প্রকারের সাথে জোর করে না। জবরদস্তি সম্ভব না হলে, #to_* পদ্ধতি অবজেক্টে প্রয়োগ করা হয় না এবং এটিকে কল করা একটি NoMethodError উত্থাপন করে .

অন্তর্নিহিত জবরদস্তি ব্যবহার করার সময়, যেমন #to_str , আমরা ফাংশনটিকে একটি স্ট্রিং অবজেক্ট ফেরত দিতে বলি, শুধুমাত্র যদি মূল প্রকারটিও একটি স্ট্রিংয়ের মতো কাজ করে। এই কারণে, #to_str রুবি স্ট্যান্ডার্ড লাইব্রেরিতে শুধুমাত্র স্ট্রিং-এ প্রয়োগ করা হয়।

রুবি কিভাবে অন্তর্নিহিত জবরদস্তি ব্যবহার করে

একটি জবরদস্তির সময় আমরা যা চাইছি তা আরও সুনির্দিষ্ট হওয়া ছাড়া, অন্তর্নিহিত জবরদস্তি আর কীসের জন্য দরকারী? দেখা যাচ্ছে রুবি মোটামুটি পরিস্থিতিতেই অন্তর্নিহিত জবরদস্তি ব্যবহার করে। উদাহরণস্বরূপ, + এর সাথে বস্তুর সমন্বয় করার সময় .

name = "world!"
"Hello " + name # => "Hello world!"
 
# Without #to_str
class Name
  def initialize(name)
    @name = name
  end
end
"Hello " + Name.new("world!") # => TypeError: no implicit conversion of Name into String

এখানে, আমরা দেখি রুবি একটি TypeError বাড়াচ্ছে যেহেতু এটি Name থেকে একটি অন্তর্নিহিত রূপান্তর করতে পারে না String এ টাইপ করুন .

যদি আমরা #to_str প্রয়োগ করি ক্লাসে, রুবি জানে কিভাবে জোর করে Name করতে হয় টাইপ করুন।

# With #to_str
class Name
  def to_str
    @name
  end
end
"Hello " + Name.new("world!") # => "Hello world!"

একই অ্যারে এবং #to_ary এর জন্য কাজ করে .

class Options
  def initialize
    @internal = []
  end
 
  def <<(value)
    @internal << value
  end
end
 
options = Options.new
options << :foo
[:some_prefix] + options # => TypeError: no implicit conversion of Options into Array
 
class Options
  def to_ary
    @internal
  end
end
[:some_prefix] + options # => [:some_prefix, :foo]

কিন্তু #to_ary আরো পরিস্থিতিতে ব্যবহার করা হয়. আমরা একটি অ্যারেকে পৃথক ভেরিয়েবলে ধ্বংস করতে এটি ব্যবহার করতে পারি।

options = Options.new
options << :first
options << :second
options << :third
first, second, third = options
first  # => :first
second # => :second
third  # => :third

এটি অবজেক্টকে ব্লক প্যারামিটারে রূপান্তরও করে।

[options].each do |(first, second)|
  first # => :first
  second # => :second
end

আরো অনেক পরিস্থিতিতে আছে যেখানে অন্তর্নিহিত জবরদস্তি পদ্ধতি ব্যবহার করা হয়, যেমন #to_hash ** সহ . এটি #to_hash সহ একটি হ্যাশের মানকে জোর করে parse_options-এ এটি পাস করার আগে পদ্ধতি।

class Options
  def to_hash
    # Create a hash from the Options Array
    Hash[*@internal]
  end
end
 
def parse_options(opts)
  opts
end
 
options = Options.new
options << :key
options << :value
parse_options(**options) # => {:key=>:value}

প্রয়োগকারী প্রকারগুলি

রুবি আরও স্থিতিস্থাপক জবরদস্তি পদ্ধতি অফার করে যখন টাইপটি একটি অজানা ধরনের হয় এবং আমরা নিশ্চিত করতে চাই যে আমরা সঠিক টাইপ পেয়েছি। প্রতিটি মৌলিক প্রকারের জন্য একটি আছে (String(...) , Integer(...) , Float(...) , Array(...) , Hash(...) , ইত্যাদি)।

String(self)       # => "main"
String(self.class) # => "Object"
String(123456)     # => "123456"
String(nil)        # => ""
 
Integer(123.999)   # => 123
Integer("0x1b")    # => 27
Integer(Time.new)  # => 1204973019
Integer(nil)       # => TypeError: can't convert nil into Integer

String(...) পদ্ধতি প্রথমে #to_str কল করার চেষ্টা করে মানের উপর, এবং যখন এটি ব্যর্থ হয়, এটি তার #to_s কল করে পদ্ধতি সমস্ত বস্তু #to_str সংজ্ঞায়িত করে না পদ্ধতি, তাই উভয় অন্তর্নিহিত জবরদস্তি (#to_str) দিয়ে পরীক্ষা করা হচ্ছে ) এবং স্পষ্ট (#to_s ) ঢালাই পদ্ধতি স্ট্রিং রূপান্তর কাজ করার সম্ভাবনা বাড়ায় এবং আপনি আপনার পছন্দসই মান পাবেন। অন্তর্নিহিত জবরদস্তির জন্য প্রথমে কল করার মাধ্যমে আমরা এমন একটি ফলাফল পাওয়ার সম্ভাবনা বেশি যা একই মান আছে কিন্তু জোরপূর্বক ধরনের, এবং "#<Object:0x00007f8e6d053a90>" এর মতো নয়। .

class MyString
  def initialize(value)
    @value = value
  end
 
  def to_str
    @value
  end
end
 
s = MyString.new("hello world")
s.to_s    # => "#<MyString:0x...>"
s.to_str  # => "hello world"
String(s) # => "hello world"

আপনার শুধুমাত্র এমন বস্তুর জন্য অন্তর্নিহিত ঢালাই পদ্ধতি প্রয়োগ করা উচিত যা বাধ্যতামূলক প্রকারের মতো কাজ করে, যেমন #to_str আপনার নিজের স্ট্রিং ক্লাসের জন্য।

প্রথমে অন্তর্নিহিত জবরদস্তির চেষ্টা করা ছাড়া, String(...) সাহায্যকারীও প্রত্যাবর্তিত প্রকার পরীক্ষা করে। #to_str শুধুমাত্র একটি পদ্ধতি যা যেকোনো ধরনের মান, এমনকি অ-স্ট্রিংগুলিও ফেরত দিতে পারে। আমরা অনুরোধ করা টাইপ String(...) এর একটি মান পেয়েছি তা নিশ্চিত করতে একটি TypeError উত্থাপন করে যদি প্রকারগুলি মেলে না।

class MyString
  def to_str
    nil
  end
end
 
s = MyString.new("hello world")
s.to_s    # => "#<MyString:0x...>"
s.to_str  # => nil
String(s) # => "#<MyString:0x...>"

এখানে, আমরা দেখতে পাচ্ছি যে রুবি #to_str এর ফলাফল উপেক্ষা করে কারণ এটি nil ফেরত দিয়েছে , যা স্ট্রিং-টাইপের নয়। পরিবর্তে, এটি #to_s-এ ফিরে আসে ফলাফল।

যদি #to_s এছাড়াও nil ফেরত দেয় এবং এইভাবে সঠিক প্রকারের নয়, String(...) একটি TypeError উত্থাপন করবে .

class MyString
  def to_str
    nil
  end
 
  def to_s
    nil
  end
end
 
s = MyString.new("hello world")
s.to_s    # => nil
s.to_str  # => nil
String(s) # => TypeError: can't convert MyString to String (MyString#to_s gives NilClass)

যদিও এগুলি টাইপ জবরদস্তি কার্যকর করার ক্ষেত্রে আরও নির্ভরযোগ্য হতে পারে, মনে রাখবেন যে কাস্টিং সহায়ক পদ্ধতিগুলি (String(...) , Integer(...) , ইত্যাদি) সাধারণত একটু ধীর হয় কারণ তাদের প্রদত্ত মানের উপর আরও চেক করতে হবে।

উপসংহারে

আপনি যখন নিশ্চিত করতে চান যে আপনি একটি বস্তুর জন্য সঠিক ধরনের ডেটা নিয়ে কাজ করছেন, টাইপ জবরদস্তি একটি দরকারী প্রক্রিয়া। এই পোস্টে, আমরা #to_s-এর মতো স্পষ্ট কাস্টিং সহায়ক সম্পর্কে আমাদের জ্ঞানকে রিফ্রেশ করেছি , #to_i , #to_a এবং #to_h . #to_str-এর মতো অন্তর্নিহিত সাহায্যকারীর উদাহরণও আমরা দেখেছি , #to_int , #to_ary এবং #to_hash দরকারী এবং কিভাবে রুবি নিজেই ব্যবহার করে।

আমরা আশা করি আপনি এই ধরনের জবরদস্তি ওভারভিউটি দরকারী বলে মনে করেছেন এবং আপনি কীভাবে অভিনেতা টাইপকাস্টিং সাদৃশ্য খুঁজে পেয়েছেন। বরাবরের মতো, আপনি আমাদের কভার করতে চান এমন কোনো বিষয় থাকলে আমাদের জানান। যদি আপনার কোন প্রশ্ন বা মন্তব্য থাকে, তাহলে আমাদের একটি লাইন @AppSignal ড্রপ করতে দ্বিধা করবেন না।


  1. রুবিতে বিটওয়াইজ হ্যাক

  2. রুবিতে ল্যাম্বডাস ব্যবহার করা

  3. রুবিতে সন্নিবেশ বাছাই বোঝা

  4. রুবি 2.6-এ 9টি নতুন বৈশিষ্ট্য