كيف أكتب طريقة للتعامل مع روبي الصفر، واحد، أو العديد من المدخلات؟
سؤال
ولقد حصلت على طريقة روبي كما يلي:
# Retrieve all fruits from basket that are of the specified kind.
def fruits_of_kind(kind)
basket.select { |f| f.fruit_type == kind.to_s }
end
والآن، يمكنك استدعاء هذه مثل:
fruits_of_kind(:apple) # => all apples in basket
fruits_of_kind('banana') # => all bananas in basket
ووهلم جرا.
وكيف أغير طريقة بحيث أنه سيتم التعامل مع المدخلات iterable وكذلك لا المدخلات والمدخلات معدومة بشكل صحيح؟ على سبيل المثال، أود أن تكون قادرة على دعم:
fruits_of_kind(nil) # => nil
fruits_of_kind(:apple, :banana) # => all apples and bananas in basket
fruits_of_kind([:apple, 'banana']) # => likewise
هل هذا ممكن القيام به اصطلاحا؟ إذا كان الأمر كذلك، ما هي أفضل طريقة لكتابة أساليب بحيث يمكن أن يقبل الصفر، واحد، أو العديد من المدخلات؟
المحلول
def fruits_of_kind(kind)
return nil if kind.nil?
result = []
([] << kind).flatten.each{|k| result << basket.select{|f| f.fruit_type == k.to_s }}
result
end
والمشغل 'تنبيه' هو على الارجح أفضل وسيلة للذهاب، ولكن هناك أمرين لمشاهدة ل: يمر في شيء أو القوائم. لتعديل حل بيستو لالإدخال / الإخراج الذي تريد، عليك أن تفعل شيئا من هذا القبيل:
def fruits_of_kind(*kinds)
return nil if kinds.compact.empty?
basket.select do |fruit|
kinds.flatten.each do |kind|
break true if fruit.fruit_type == kind.to_s
end == true #if no match is found, each returns the whole array, so == true returns false
end
end
إذا كنت تمر في شيء، و* تحولها إلى [لا شيء]. إذا كنت ترغب في العودة لا شيء بدلا من قائمة فارغة، لديك لضغط عليه (إزالة الأصفار) إلى []، ثم يعود لا شيء إذا كان فارغا.
إذا كنت تمر في القائمة، مثل [: التفاح، 'الموز']، و* تحولها إلى [[: التفاح، 'الموز']]. انها فرق دقيق، بل انها قائمة عنصر واحد يحتوي على قائمة أخرى، لذلك تحتاج إلى تتسطح أنواع قبل القيام "كل" حلقة. تسطيح وتحويله إلى [: التفاح، 'الموز']، مثل تتوقع، وتعطيك النتائج التي تبحث عنها
تعديل : لوحتى أفضل، وذلك بفضل جريج كامبل:
def fruits_of_kind(basket, kind)
return nil if kind.nil?
kind_list = ([] << kind).flatten.map{|kind| kind.to_s}
basket.select{|fruit| kind_list.include?(fruit) }
end
وOR (باستخدام تنبيه)
def fruits_of_kind(*kinds)
return nil if kinds.compact.empty?
kind_list = kinds.flatten.map{|kind| kind.to_s}
basket.select{|fruit| kind_list.include?(fruit.fruit_type) }
end
نصائح أخرى
وتحتاج إلى استخدام المشغل تنبيه روبي، التي يلتف كل الحجج المتبقية في صفيف وينقلها في:
def foo (a, b, *c)
#do stuff
end
foo(1, 2) # a = 1, b = 2, c = []
foo(1, 2, 3, 4, 5) #a = 1, b = 2, c = [3, 4, 5]
في الحالة الخاصة بك، يجب أن شيئا مثل هذا العمل:
def fruits_of_kind(*kinds)
kinds.flatten!
basket.select do |fruit|
kinds.each do |kind|
break true if fruit.fruit_type == kind.to_s
end == true #if no match is found, each returns the whole array, so == true returns false
end
end
تحرير
ولقد غيرت رمز لشد أنواع بحيث يمكنك إرسال في القائمة. وهذا الرمز التعامل دخول أي أنواع في كل شيء، ولكن إذا كنت تريد أن ينص صراحة المدخلات nil
، إضافة kinds = [] if kinds.nil?
الخط في البداية.
استخدم ميزة VARARGS روبي.
# Retrieve all fruits from basket that are of the specified kind.
# notice the * prefix used for method parameter
def fruits_of_kind(*kind)
kind.each do |x|
puts x
end
end
fruits_of_kind(:apple, :orange)
fruits_of_kind()
fruits_of_kind(nil)
و-sasuke
وهناك استخدام معبرة بشكل رائع من تنبيه كحجة لإنشاء مجموعة الذي يعالج المثال الأخير:
def foo(may_or_may_not_be_enumerable_arg)
arrayified = [*may_or_may_not_be_enumerable_arg]
arrayified.each do |item|
puts item
end
end
obj = "one thing"
objs = ["multiple", "things", 1, 2, 3]
foo(obj)
# one thing
# => ["one thing"]
foo(objs)
# multiple
# things
# 1
# 2
# 3
# => ["multiple", "things", 1, 2, 3]