রুবির ডুপ এবং ক্লোন পদ্ধতির মধ্যে পার্থক্য কী?


214

জন্য রুবি ডক্সdup বলে:

সাধারণভাবে, cloneএবং dupবংশোদ্ভূত শ্রেণিতে বিভিন্ন শব্দার্থবিজ্ঞান থাকতে পারে। যদিও cloneতার অভ্যন্তরীণ স্থিতি সহ একটি বস্তু, নকল করতে ব্যবহার করা হয়, dupসাধারণত নতুন উদাহরণ সৃষ্টি করতে বংশধর বস্তুর শ্রেণী ব্যবহার করে।

তবে যখন আমি কিছু পরীক্ষা করি তখন দেখতে পেলাম যে তারা আসলে একই রকম:

class Test
   attr_accessor :x
end

x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7

সুতরাং দুটি পদ্ধতির মধ্যে পার্থক্য কি?


29
আমি আশা করি আমি কী dup এবং কীগুলির মধ্যে পার্থক্য না জানতাম cloneতবে কেন আপনি অন্যটির চেয়ে একটি ব্যবহার করতেন।
অ্যান্ড্রু গ্রিম

উত্তর:


298

সাবক্লাসগুলি বিভিন্ন শব্দার্থবিজ্ঞান সরবরাহ করতে এই পদ্ধতিগুলিকে ওভাররাইড করতে পারে। ইন Objectনিজেই, দুই মূল পার্থক্য আছে।

প্রথমে cloneসিঙ্গলটন ক্লাস অনুলিপি করে, যখন dupনা হয়।

o = Object.new
def o.foo
  42
end

o.dup.foo   # raises NoMethodError
o.clone.foo # returns 42

দ্বিতীয়ত, cloneহিমশীতল সংরক্ষণ করে, যখন dupহয় না।

class Foo
  attr_accessor :bar
end
o = Foo.new
o.freeze

o.dup.bar = 10   # succeeds
o.clone.bar = 10 # raises RuntimeError

এই পদ্ধতি জন্য Rubinius বাস্তবায়ন প্রায়ই এসব প্রশ্নের উত্তর আমার উৎস, যেহেতু এটি বেশ স্পষ্ট, এবং একটি মোটামুটি অনুবর্তী রুবি বাস্তবায়ন।


15
যদি কেউ আবারও এটি পরিবর্তন করার চেষ্টা করে: "সিঙ্গেলটন ক্লাস", যা রুবির একটি সুস্পষ্ট সংজ্ঞায়িত শব্দ, কেবল সিঙ্গলটন পদ্ধতিই নয় , সিঙ্গলটন শ্রেণিতে সংজ্ঞায়িত কোনও ধ্রুবককেও অন্তর্ভুক্ত করে। বিবেচনা করুন: o = Object.new; class << o; A=5; end; puts ( class << o.clone; A; end ); puts ( class << o.dup; A; end )
জেরেমি রোমান

3
দুর্দান্ত উত্তর, তারপরে একটি দুর্দান্ত মন্তব্য, তবে এটি আমাকে সিনট্যাক্স বোঝার জন্য বন্য হংসের তাড়াতে পরিচালিত করেছিল। এটি সেখানে অন্য যে কোনও ব্যক্তিকেও যে বিভ্রান্ত হতে পারে তা সহায়তা করবে: devalot.com/articles/2008/09/ruby-singleton
ডেভিড পিএম 4

1
আমি মনে করি এটি উল্লেখ করার মতো যে "সিঙ্গেলটন শ্রেণিতে" এমন কোনও মডিউলও রয়েছে extendযা মূল অবজেক্টে সম্পাদিত হয়েছিল। সুতরাং Object.new.extend(Enumerable).dup.is_a?(Enumerable)মিথ্যা প্রত্যাবর্তন।
ড্যানিয়েল

যদিও এই উত্তরগুলি প্রশ্নের উত্তর দেয় এবং পার্থক্য উল্লেখ করে। এটি লক্ষ্য করার মতো বিষয়ও যে উভয় পদ্ধতিই বিভিন্ন পরিস্থিতির জন্য বোঝানো হয়েছে অবজেক্ট # ডুপ ডকুমেন্টেশন দ্বারা। ক্লোনটির জন্য ব্যবহারের ক্ষেত্রে কোনও অবজেক্টটিকে একই উদাহরণ হিসাবে ব্যবহারের উদ্দেশ্য হিসাবে ক্লোনিং করা হচ্ছে (ভিন্ন ভিন্ন আইডি থাকা অবস্থায়), যখন ডুপের উদ্দেশ্যটি কোনও নতুন উদাহরণের জন্য ভিত্তি হিসাবে কোনও বিষয়টিকে নকল করতে পারে।
3limin4t0r

189

অ্যাক্টিভেকর্ডের সাথে কাজ করার সময় একটি উল্লেখযোগ্য পার্থক্য রয়েছে:

dup এটির আইডি সেট না করেই একটি নতুন অবজেক্ট তৈরি করে, যাতে আপনি হিট করে ডাটাবেজে একটি নতুন অবজেক্টটি সংরক্ষণ করতে পারেন .save

category2 = category.dup
#=> #<Category id: nil, name: "Favorites"> 

clone একই আইডি সহ একটি নতুন অবজেক্ট তৈরি করে, সুতরাং নতুন আইটে থাকা সমস্ত পরিবর্তনগুলি যদি আঘাত করে তবে মূল রেকর্ডটি ওভাররাইট করে .save

category2 = category.clone
#=> #<Category id: 1, name: "Favorites">

43
এই উত্তরটি হ'ল আইএমওর সবচেয়ে গুরুত্বপূর্ণ ব্যবহারিক তথ্য ... অন্য উত্তরগুলি এসোটেরিকার উপর নির্ভর করে, যদিও এই উত্তরটি একটি গুরুত্বপূর্ণ ব্যবহারিক পার্থক্যটিকে নির্দেশ করে।
jpw

37
উপরেরটি অ্যাক্টিভেকর্ডের ক্ষেত্রে নির্দিষ্ট; পার্থক্যটি মানক রুবির তুলনায় আরও সূক্ষ্ম।
আহমকালোড

1
@ স্টেফান এবং @ জাভালেনেন: যখন আমি আমার বিষয়টিতে প্রয়োগ করি dupএবং cloneপদ্ধতিগুলি ব্যবহার করি তখন ActiveRecordআপনি উত্তরে যা উল্লেখ করেছেন তার বিপরীত ফলাফল পাচ্ছি। যার অর্থ যখন আমি ব্যবহার করছি তখন dupএটি idসেট হয়ে যাওয়ার সাথে একটি নতুন অবজেক্ট cloneতৈরি করে এবং এটি ব্যবহার করার সময় সেট না করেই একটি অবজেক্ট তৈরি করে id। আপনি দয়া করে এটি আবার দেখুন এবং পরিষ্কার করতে পারেন? । Thnx
biyawarwala huzefa

5 রেলগুলিতে কোনও কিছুই পরিবর্তিত হয়নি: api.rubyonrails.org/classes/ActiveRecord/… । সুতরাং আমি বিশ্বাস করি আপনার ক্ষেত্রে বিশেষ কিছু আছে ...
jvalanen

যাইহোক, cloneনতুন রেকর্ডটি তৈরি করা যা কখনও সংরক্ষণ করা যায় নি তখন কি নিরাপদ থাকা উচিত? আমি কি এইভাবে কোনও "টেম্পলেট অবজেক্ট" তৈরি করতে পারি এবং নির্দিষ্ট দৃষ্টান্তগুলি সংরক্ষণ করতে এটি ক্লোন করতে পারি?
সিরিল ডুচন-ডরিস

30

এক পার্থক্য হিমায়িত অবজেক্টের সাথে। cloneএকটি হিমায়িত বস্তুর এছাড়াও নিথর হয় (যেহেতু একটি dupএকটি হিমায়িত বস্তুর নয়)।

class Test
  attr_accessor :x
end
x = Test.new
x.x = 7
x.freeze
y = x.dup
z = x.clone
y.x = 5 => 5
z.x = 5 => TypeError: can't modify frozen object

আর একটি পার্থক্য হ'ল সিঙ্গলটন পদ্ধতিগুলির সাথে। এখানে একই গল্প, dupসেগুলি অনুলিপি করে না, তবে cloneকরে।

def x.cool_method
  puts "Goodbye Space!"
end
y = x.dup
z = x.clone
y.cool_method => NoMethodError: undefined method `cool_method'
z.cool_method => Goodbye Space!

এটি আমার জন্য খুব দরকারী ছিল। যদি আপনি একটি হিমায়িত ধ্রুবক মান তৈরি করে এবং এটিকে এমন কিছুতে পৌঁছে দেন : github.com/rack/rack/blob/master/lib/rack/utils.rb#L248 (রেল কুকি হ্যান্ডলিং) তবে আপনি সহজেই একটি ত্রুটি পেতে পারেন যখন তারা আপনার অজানাতে তারা এটিকে ক্লোন করে এবং তারপরে ক্লোনটি সংশোধন করার চেষ্টা করে। আপনার হিমশীতল মূল্য ডুবিয়ে দেওয়া এবং এটি পাস করা আপনাকে কমপক্ষে গ্যারান্টি দেওয়ার অনুমতি দেয় যে কোনও রাক এখানে ভাঙা ছাড়াই দুর্ঘটনাবশত আপনার ধ্রুবককে কোনও পরিবর্তন করে না।
এক্সপি 84

4

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

 f = 'Frozen'.freeze
  => "Frozen"
 f.frozen?
  => true 
 f.clone.frozen?
  => true
 f.dup.frozen?
  => false 

4

নতুন ডক একটি ভাল উদাহরণ রয়েছে:

class Klass
  attr_accessor :str
end

module Foo
  def foo; 'foo'; end
end

s1 = Klass.new #=> #<Klass:0x401b3a38>
s1.extend(Foo) #=> #<Klass:0x401b3a38>
s1.foo #=> "foo"

s2 = s1.clone #=> #<Klass:0x401b3a38>
s2.foo #=> "foo"

s3 = s1.dup #=> #<Klass:0x401b3a38>
s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401b3a38>

0

আপনি রুবিতে প্রোটোটাইপ-ভিত্তিক প্রোগ্রামিং করতে ক্লোন ব্যবহার করতে পারেন। রুবির অবজেক্ট ক্লাস ক্লোন পদ্ধতি এবং ডুপ পদ্ধতি উভয়কেই সংজ্ঞায়িত করে। ক্লোন এবং ডুপ উভয়ই এটি অনুলিপি করছে এমন একটি অগভীর অনুলিপি তৈরি করে; অর্থাৎ, বস্তুর উদাহরণের ভেরিয়েবলগুলি অনুলিপি করা হয় তবে তারা যে বস্তুগুলি উল্লেখ করে তা নয়। আমি একটি উদাহরণ প্রদর্শন করব:

class Apple
  attr_accessor :color
  def initialize
    @color = 'red'
  end
end

apple = Apple.new
apple.color
 => "red"
orange = apple.clone
orange.color 
 => "red"
orange.color << ' orange'
 => "red orange" 
apple.color
 => "red orange"

উপরের উদাহরণে লক্ষ্য করুন, কমলা ক্লোনটি আপেল বস্তুর রাজ্যের (অর্থাত্ ভেরিয়েবলগুলি) অনুলিপি করে, তবে যেখানে আপেল বস্তু অন্যান্য বস্তুর (যেমন স্ট্রিং অবজেক্ট রঙ) উল্লেখ করে সেখানে সেই উল্লেখগুলি অনুলিপি করা হয় না। পরিবর্তে, আপেল এবং কমলা উভয় একই বস্তুর রেফারেন্স! আমাদের উদাহরণস্বরূপ, রেফারেন্সটি হল স্ট্রিং অবজেক্ট 'লাল'। কমলা যখন বিদ্যমান স্ট্রিং অবজেক্টটি সংশোধন করতে <<, সংযোজন পদ্ধতিটি ব্যবহার করে, তখন স্ট্রিং অবজেক্টটিকে 'লাল কমলা'তে পরিবর্তন করা হয়। এটি কার্যকরভাবে আপেল-রঙকেও পরিবর্তন করে, যেহেতু তারা উভয়ই একই স্ট্রিং অবজেক্টের দিকে নির্দেশ করছে।

পার্শ্ব নোট হিসাবে, অ্যাসাইনমেন্ট অপারেটর =, একটি নতুন অবজেক্ট বরাদ্দ করবে এবং এইভাবে একটি রেফারেন্স নষ্ট করবে। এখানে একটি বিক্ষোভ:

class Apple
  attr_accessor :color
  def initialize
    @color = 'red'
  end
end

apple = Apple.new
apple.color
=> "red"
orange = apple.clone
orange.color
=> "red"
orange.color = 'orange'
orange.color
=> 'orange'
apple.color
=> 'red'

উপরের উদাহরণে, যখন আমরা কমলা রঙের ক্লোনার রঙ উদাহরণ পদ্ধতিতে একটি নতুন নতুন অবজেক্টকে অর্পণ করি তখন এটি আর আপেলের মতো একই বস্তুর উল্লেখ করে না। অতএব, আমরা এখন আপেলের রঙ পদ্ধতিকে প্রভাবিত না করে কমলার রঙের পদ্ধতিটি পরিবর্তন করতে পারি, তবে আমরা যদি আপেল থেকে অন্য কোনও বস্তুর ক্লোন করি, তবে নতুন বস্তুটি আপেল হিসাবে অনুলিপিভুক্ত ভেরিয়েবলগুলিতে একই বস্তুটিকে উল্লেখ করবে।

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

class Apple
  attr_accessor :color
  def initialize
    @color = 'red'
  end
end

apple = Apple.new
apple.frozen?
 => false 
apple.freeze
apple.frozen?
 => true 
apple.color = 'crimson'
RuntimeError: can't modify frozen Apple
apple.color << ' crimson' 
 => "red crimson" # we cannot modify the state of the object, but we can certainly modify objects it is referencing!
orange = apple.dup
orange.frozen?
 => false 
orange2 = apple.clone
orange2.frozen?
 => true 
orange.color = 'orange'
 => "orange" # we can modify the orange object since we used dup, which did not copy the frozen state
orange2.color = 'orange'
RuntimeError: can't modify frozen Apple # orange2 raises an exception since the frozen state was copied via clone

দ্বিতীয়, এবং আরও মজার বিষয় হল, ক্লোন সিঙ্গলটন ক্লাসের অনুলিপি করেছে (এবং এর ফলে এর পদ্ধতিগুলি)! আপনি যদি রুবিতে প্রোটোটাইপ-ভিত্তিক প্রোগ্রামিং করতে চান তবে এটি খুব কার্যকর। প্রথমে দেখা যাক যে প্রকৃতপক্ষে সিঙ্গলটন পদ্ধতিগুলি ক্লোন দিয়ে অনুলিপি করা হয়েছে এবং তারপরে আমরা এটি রুবিতে প্রোটোটাইপ-ভিত্তিক প্রোগ্রামিংয়ের উদাহরণে প্রয়োগ করতে পারি।

class Fruit
  attr_accessor :origin
  def initialize
    @origin = :plant
  end
end

fruit = Fruit.new
 => #<Fruit:0x007fc9e2a49260 @origin=:plant> 
def fruit.seeded?
  true
end
2.4.1 :013 > fruit.singleton_methods
 => [:seeded?] 
apple = fruit.clone
 => #<Fruit:0x007fc9e2a19a10 @origin=:plant> 
apple.seeded?
 => true 

আপনি দেখতে পাচ্ছেন, ফলের অবজেক্টের উদাহরণটির সিঙ্গলটন ক্লাসটি ক্লোনটিতে অনুলিপি করা হয়েছে। এবং তাই ক্লোনযুক্ত বস্তুর একক পদ্ধতিতে প্রবেশ রয়েছে: বীজযুক্ত ?. তবে ডুপের ক্ষেত্রে এটি হয় না:

apple = fruit.dup
 => #<Fruit:0x007fdafe0c6558 @origin=:plant> 
apple.seeded?
=> NoMethodError: undefined method `seeded?'

এখন প্রোটোটাইপ-ভিত্তিক প্রোগ্রামিংয়ে আপনার কাছে এমন ক্লাস নেই যা অন্যান্য ক্লাসগুলি প্রসারিত করে এবং তারপরে ক্লাসগুলির উদাহরণ তৈরি করে যার পদ্ধতিগুলি পিতামাত্ত শ্রেণীর কাছ থেকে উদ্ভূত হয় যা একটি নীলনকশা হিসাবে কাজ করে। পরিবর্তে, আপনার একটি বেস অবজেক্ট রয়েছে এবং তারপরে আপনি তার পদ্ধতিগুলি সহ রাষ্ট্রটি অনুলিপি করে একটি নতুন অবজেক্ট তৈরি করুন (অবশ্যই, যেহেতু আমরা ক্লোনটির মাধ্যমে অগভীর অনুলিপিগুলি করছি, কোনও বস্তুর উদাহরণ ভেরিয়েবলের রেফারেন্সটি জাভাস্ক্রিপ্টের মতো ভাগ করা হবে) এগুলির নমুনা)। তারপরে ক্লোন পদ্ধতিগুলির বিশদ পূরণ করে আপনি বস্তুর স্থিতি পূরণ বা পরিবর্তন করতে পারেন। নীচের উদাহরণে, আমাদের একটি বেস ফলের অবজেক্ট রয়েছে। সমস্ত ফলের বীজ থাকে, তাই আমরা একটি পদ্ধতি সংখ্যা_সামান্য তৈরি করি। তবে আপেলের একটি বীজ থাকে এবং তাই আমরা একটি ক্লোন তৈরি করি এবং বিশদটি পূরণ করি। এখন যখন আমরা আপেল ক্লোন করি, আমরা কেবল পদ্ধতিগুলি ক্লোন করেইছিলাম না তবে আমরা রাজ্যের ক্লোন করেছিলাম! মনে রাখবেন ক্লোনটি রাষ্ট্রের অগভীর অনুলিপি করে (উদাহরণস্বরূপ ভেরিয়েবল)। এবং তার কারণ হিসাবে, যখন আমরা একটি রেড_্যাপল পেতে আপেল ক্লোন করব তখন লাল_ অ্যাপলটিতে স্বয়ংক্রিয়ভাবে 1 টি বীজ থাকবে! আপনি রেড_এপলকে অ্যাপল হিসাবে উত্তরাধিকার সূত্রে প্রাপ্ত একটি বিষয় হিসাবে ভাবতে পারেন, ফলস্বরূপ ফল থেকে প্রাপ্ত হয়। সুতরাং, আমি ফল এবং অ্যাপলকে মূলধন করেছিলাম। ক্লোন এবং সৌজন্যে ক্লোনটির অবজেক্টের মধ্যে পার্থক্যটি আমরা সরিয়ে দিয়েছি।

Fruit = Object.new
def Fruit.number_of_seeds=(number_of_seeds)
  @number_of_seeds = number_of_seeds
end
def Fruit.number_of_seeds
  @number_of_seeds
end
 Apple = Fruit.clone
 => #<Object:0x007fb1d78165d8> 
Apple.number_of_seeds = 1
Apple.number_of_seeds
=> 1
red_apple = Apple.clone
 => #<Object:0x007fb1d892ac20 @number_of_seeds=1> 
red_apple.number_of_seeds
 => 1 

অবশ্যই, আমাদের প্রোটোপ-ভিত্তিক প্রোগ্রামিংয়ে একটি কনস্ট্রাক্টর পদ্ধতি থাকতে পারে:

Fruit = Object.new
def Fruit.number_of_seeds=(number_of_seeds)
  @number_of_seeds = number_of_seeds
end
def Fruit.number_of_seeds
  @number_of_seeds
end
def Fruit.init(number_of_seeds)
  fruit_clone = clone
  fruit_clone.number_of_seeds = number_of_seeds
  fruit_clone
end
Apple = Fruit.init(1)
 => #<Object:0x007fcd2a137f78 @number_of_seeds=1> 
red_apple = Apple.clone
 => #<Object:0x007fcd2a1271c8 @number_of_seeds=1> 
red_apple.number_of_seeds
 => 1 

শেষ পর্যন্ত, ক্লোন ব্যবহার করে, আপনি জাভাস্ক্রিপ্ট প্রোটোটাইপ আচরণের অনুরূপ কিছু পেতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.