المساواة والتجزئة
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 37 من 57.
لدى Ruby عدة أنواع من المساواة. == هي مساواة القيم، التي تعرّفها لفئتك. تستخدم Hashes وuniq طريقتين أخريين بدلًا من ذلك: eql? وhash. عند تعريف == فقط، تظل النقاط المتساوية مفاتيح مختلفة في التجزئة:
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)
b = Point.new(1, 2)
puts a == b
puts [a, b].uniq.size
puts({ a => "first" }[b].inspect)الناتج:
true
2
nilيقارن Hash أولًا قيم hash، وهي أرقام محسوبة من كائن، ثم يتحقق من المرشحين باستخدام eql?. عرّف كليهما باستخدام الحقول نفسها المستخدَمة في ==. يعيد alias eql? == استخدام ==، بينما تجمع [x, y].hash الحقول:
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
alias eql? ==
def hash
[x, y].hash
end
end
a = Point.new(1, 2)
b = Point.new(1, 2)
puts [a, b, Point.new(3, 4)].uniq.size
puts({ a => "first" }[b])الناتج:
2
firstالقاعدة هي: يجب أن يكون للكائنات التي eql? القيمة نفسها في hash. قد تشترك كائنات مختلفة في قيمة hash بالصدفة، ولهذا السبب يستمر eql? في التحقّق. بعد ذلك، يعمل العد باستخدام Hash على القيم بدلًا من الهويات:
class Word
attr_reader :text
def initialize(text)
@text = text.downcase
end
def ==(other)
other.is_a?(Word) && text == other.text
end
alias eql? ==
def hash
text.hash
end
end
counts = Hash.new(0)
%w[Ruby ruby RUBY gem].each { |t| counts[Word.new(t)] += 1 }
counts.each { |word, n| puts "#{word.text}: #{n}" }الناتج:
ruby: 3
gem: 1يظل equal? خاصًا بالهوية، ولا ينبغي أبدًا إعادة تعريفه. تتبع القيم المضمّنة هذه القواعد بالفعل، ولهذا السبب تعمل السلاسل والمصفوفات كمفاتيح للتجزئة:
a == b # نفس القيمة (أنت تعرّفها)
a.eql?(b) # نفس القيمة لمفاتيح Hash و uniq (اسم مستعار لـ ==)
a.hash # رقم؛ الكائنات المتساوية تعطي أرقامًا متساوية
a.equal?(b) # نفس الكائن (لا تعِد تعريفه أبدًا)التحدي
سهلأكمل الصنف Point بحيث تكون النقاط ذات الإحداثيات نفسها متساوية باستخدام == وeql? وhash، وتعمل كمفاتيح في Hash. تُرجع to_s القيمة (1, 2).
يقرأ الكود المزوَّد النقاط على شكل أسطر x,y. ويطبع عدد النقاط المميّزة باستخدام uniq، ثم يحسب عدد الزيارات لكل نقطة في Hash ويطبعها بترتيب الزيارة الأولى على الشكل (1, 2): 2، وأخيرًا يطبع ما إذا كان Point.new(0, 0) الجديد مفتاحًا.
ضع كودك في 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)) }
puts "distinct: #{points.uniq.size}"
visits = Hash.new(0)
points.each { |pt| visits[pt] += 1 }
visits.each { |pt, n| puts "#{pt}: #{n}" }
puts "origin visited: #{visits.key?(Point.new(0, 0))}"
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت