المساواة والتجزئة
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 37 من 57.
لدى Ruby عدة أنواع من المساواة. == هي مساواة القيم، التي تعرّفها لفئتك. تستخدم التجزئات و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 عبر الإنترنت