Menu
CoddyTech

الهوية والمساواة

جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 10 من 57.

يحتفظ المتغير بمرجع إلى كائن، وليس بالكائن نفسه. يؤدي إسناده إلى متغير آخر إلى نسخ المرجع، لذا يشير الاسمان بعد ذلك إلى الكائن نفسه:

class Box
  attr_accessor :count

  def initialize
    @count = 0
  end
end

a = Box.new
b = a
b.count += 1
puts a.count

الناتج:

1

يسأل equal? عمّا إذا كان مرجعان يشيران إلى الكائن نفسه، ويمثّل object_id الرقم الفريد لكل كائن. في الأصناف التي تنشئها بنفسك، ينفّذ == الأمر نفسه افتراضيًا، لذا لا يكون كائنان لهما القيم نفسها متساويين:

class Point
  attr_reader :x, :y

  def initialize(x, y)
    @x = x
    @y = y
  end
end

a = Point.new(1, 2)
b = Point.new(1, 2)
c = a
puts a == b
puts a.equal?(b)
puts a.equal?(c)
puts a.object_id == c.object_id

الناتج:

false
false
true
true

عرّف == للمقارنة حسب القيمة. تستخدم include? وindex وdelete على المصفوفات ==، لذا ستعثر عندئذٍ على الكائنات المتساوية أيضًا. تحقّق أولًا من فئة other، حتى تُرجع المقارنة مع رقم أو nil القيمة false بدلًا من أن تفشل:

class Point
  attr_reader :x, :y

  def initialize(x, y)
    @x = x
    @y = y
  end

  def ==(other)
    other.is_a?(Point) && x == other.x && y == other.y
  end
end

a = Point.new(1, 2)
puts a == Point.new(1, 2)
puts a == 5
puts [Point.new(0, 0), Point.new(1, 2)].include?(a)
puts a.equal?(Point.new(1, 2))

الناتج:

true
false
true
false

تنشئ dup كائنًا جديدًا بنسخ متغيرات النسخة. يؤدي تعيين قيمة جديدة في النسخة إلى إبقاء الأصل كما هو، لكن المصفوفة أو السلسلة النصية الموجودة بداخلها تظل مشتركة بين الاثنين، لأن ما نُسخ هو المرجع فقط:

class Team
  attr_accessor :name, :players

  def initialize(name)
    @name = name
    @players = []
  end
end

a = Team.new("Reds")
b = a.dup
b.name = "Blues"
b.players << "Ada"
puts a.name
p a.players

الناتج:

Reds
["Ada"]
challenge icon

التحدي

سهل

أكمل الصنف Point بحيث تكون نقطتان لهما الإحداثيات نفسها متساويتين عند استخدام ==، وتُرجع مقارنة نقطة بأي شيء آخر false. تُرجع to_s القيمة (1, 2).

يقرأ الكود المقدَّم النقاط على هيئة أسطر بالتنسيق x,y. ولكل نقطة، يطبع (1, 2) same as first: true أو false، ثم يحتفظ بقائمة من النقاط المتميزة باستخدام include?، وأخيرًا يطبع distinct: 3 وما إذا كانت النقطة الأولى تساوي النص "1,2".

ضع الكود في point.rb. يحتوي main.rb على كود الإدخال/الإخراج المقدَّم، ولا يمكن تعديله.

جرّب بنفسك

require_relative 'point'

# كود الإدخال/الإخراج الموفَّر: اتركه كما هو
input = []
while (line = gets)
  input << line.chomp
end
points = input.map { |line| Point.new(*line.split(",").map(&:to_i)) }
points.each { |pt| puts "#{pt} same as first: #{pt == points[0]}" }
distinct = []
points.each { |pt| distinct << pt unless distinct.include?(pt) }
puts "distinct: #{distinct.size}"
puts "equals text: #{points[0] == input[0]}"
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Ruby عبر الإنترنت