แทนที่จะสนับสนุนเมธอด overloading Ruby จะเขียนทับเมธอดที่มีอยู่ ทุกคนสามารถอธิบายได้หรือไม่ว่าทำไมภาษานี้ได้รับการออกแบบในลักษณะนี้?
แทนที่จะสนับสนุนเมธอด overloading Ruby จะเขียนทับเมธอดที่มีอยู่ ทุกคนสามารถอธิบายได้หรือไม่ว่าทำไมภาษานี้ได้รับการออกแบบในลักษณะนี้?
คำตอบ:
วิธีการบรรทุกเกินพิกัดสามารถทำได้โดยการประกาศสองวิธีที่มีชื่อเดียวกันและลายเซ็นที่แตกต่างกัน ลายเซ็นที่แตกต่างเหล่านี้สามารถเป็นได้ทั้ง
method(int a, int b) vs method(String a, String b)
method(a) vs method(a, b)
เราไม่สามารถใช้วิธีการมากเกินไปได้โดยใช้วิธีแรกเนื่องจากไม่มีการประกาศชนิดข้อมูลเป็นทับทิม ( ภาษาที่พิมพ์แบบไดนามิก ) ดังนั้นวิธีเดียวที่จะกำหนดวิธีการข้างต้นคือdef(a,b)
ด้วยตัวเลือกที่สองอาจดูเหมือนว่าเราสามารถใช้วิธีการมากไป แต่เราทำไม่ได้ สมมุติว่าฉันมีสองวิธีที่มีจำนวนอาร์กิวเมนต์ต่างกัน
def method(a); end;
def method(a, b = true); end; # second argument has a default value
method(10)
# Now the method call can match the first one as well as the second one,
# so here is the problem.
ดังนั้นทับทิมจำเป็นต้องรักษาวิธีหนึ่งในวิธีการค้นหาห่วงโซ่ที่มีชื่อที่ไม่ซ้ำกัน
"การบรรทุกเกินพิกัด" เป็นคำศัพท์ที่ไม่มีความหมายในรูบี มันเป็นพื้นไวพจน์ "ส่งข้อโต้แย้งตามคงที่" แต่ทับทิมไม่ได้มีการจัดส่งแบบคงที่ทั้งหมด ดังนั้นเหตุผลที่ทับทิมไม่สนับสนุนการแจกแจงแบบคงที่ตามข้อโต้แย้งเพราะมันไม่สนับสนุนการแจกแจงคงที่ระยะเวลา มันไม่รองรับการส่งแบบคงที่ทุกชนิดไม่ว่าจะตามอาร์กิวเมนต์หรืออย่างอื่น
ตอนนี้ถ้าคุณไม่ได้ถามเฉพาะเกี่ยวกับการบรรทุกเกินพิกัด แต่อาจเกี่ยวกับการจัดส่งตามอาร์กิวเมนต์แบบไดนามิกคำตอบคือ: เนื่องจาก Matz ไม่ได้ใช้งาน เพราะไม่มีใครสนใจที่จะเสนอ เพราะไม่มีใครสนใจที่จะใช้มัน
โดยทั่วไปการจัดส่งอาร์กิวเมนต์ตามแบบไดนามิกในภาษาที่มีการขัดแย้งที่ไม่จำเป็นและรายการอาร์กิวเมนต์ตัวแปรที่มีความยาวเป็นอย่างมากยากที่จะได้รับสิทธิและแม้ยากที่จะให้มันเข้าใจ แม้ในภาษาที่มีการแจกแจงแบบอิงอาร์กิวเมนต์แบบคงที่และไม่มีอาร์กิวเมนต์ที่เป็นตัวเลือก (เช่น Java เป็นต้น) บางครั้งแทบเป็นไปไม่ได้เลยที่จะบอกว่าเป็นเพียงมนุษย์ธรรมดาซึ่งจะมีการเลือกเกินพิกัด
ใน C # คุณสามารถเข้ารหัสปัญหา 3-SAT ใด ๆลงในการแก้ปัญหาการโอเวอร์โหลดซึ่งหมายความว่าการแก้ไขการโอเวอร์โหลดใน C # นั้นเป็น NP-hard
ตอนนี้ให้ลองด้วยการจัดส่งแบบไดนามิกที่คุณมีมิติเวลาเพิ่มเติมเพื่อให้อยู่ในหัวของคุณ
มีภาษาที่จัดส่งแบบไดนามิกตามข้อโต้แย้งทั้งหมดของขั้นตอนเมื่อเทียบกับภาษาเชิงวัตถุซึ่งส่งเฉพาะในself
ข้อโต้แย้งซีร็อ ธ "ซ่อน" ยกตัวอย่างเช่น Common Lisp ในประเภทแบบไดนามิกและแม้กระทั่งค่าแบบไดนามิกของการขัดแย้งทั้งหมด Clojure ยื้อกับฟังก์ชั่นโดยพลการของข้อโต้แย้งทั้งหมด (ซึ่ง BTW จะเย็นมากและมีประสิทธิภาพมาก)
แต่ฉันไม่รู้ภาษา OO ใด ๆ กับการแจกจ่ายตามอาร์กิวเมนต์แบบไดนามิก มาร์ตินโอเดอร์ สกี บอกว่าเขาอาจพิจารณาเพิ่มการจัดส่งอาร์กิวเมนต์ที่ใช้ในการ Scala แต่เพียงว่าเขาสามารถลบมากไปในเวลาเดียวกันและจะย้อนกลับเข้ากันได้ทั้งที่มีอยู่รหัสสกาล่าที่ใช้มากไปและเข้ากันได้กับ Java (เขากล่าวถึงโดยเฉพาะอย่างยิ่ง Swing และ AWT ซึ่งเล่นเทคนิคที่ซับซ้อนมากบางอย่างออกกำลังกายสวยมากทุกกรณีมุมมืดของกฎการโอเวอร์โหลดค่อนข้างซับซ้อนของ Java) ฉันมีความคิดบางอย่างเกี่ยวกับการเพิ่มการส่งแบบอิงอาร์กิวเมนต์ไปที่ Ruby แต่ฉันไม่สามารถหาวิธีที่จะทำในลักษณะที่เข้ากันได้ย้อนหลัง
def method(a, b = true)
ไม่ทำงาน" ดังนั้นการโอเวอร์โหลดวิธีจึงเป็นไปไม่ได้ " มันไม่ใช่; มันเป็นเรื่องยาก ฉันพบคำตอบนี้ให้ข้อมูลจริงๆ
ฉันคิดว่าคุณกำลังมองหาความสามารถในการทำเช่นนี้:
def my_method(arg1)
..
end
def my_method(arg1, arg2)
..
end
Ruby สนับสนุนสิ่งนี้ในวิธีที่แตกต่าง:
def my_method(*args)
if args.length == 1
#method 1
else
#method 2
end
end
รูปแบบทั่วไปก็จะผ่านในตัวเลือกเป็นแฮ:
def my_method(options)
if options[:arg1] and options[:arg2]
#method 2
elsif options[:arg1]
#method 1
end
end
my_method arg1: 'hello', arg2: 'world'
หวังว่าจะช่วย
วิธีการบรรทุกเกินพิกัดทำให้รู้สึกในภาษาที่มีการพิมพ์แบบคงที่ซึ่งคุณสามารถแยกความแตกต่างระหว่างประเภทของการขัดแย้ง
f(1)
f('foo')
f(true)
เช่นเดียวกับระหว่างจำนวนอาร์กิวเมนต์ที่ต่างกัน
f(1)
f(1, 'foo')
f(1, 'foo', true)
ความแตกต่างแรกไม่มีอยู่ในทับทิม Ruby ใช้การพิมพ์แบบไดนามิกหรือ "การพิมพ์เป็ด" ความแตกต่างที่สองสามารถจัดการได้โดยอาร์กิวเมนต์เริ่มต้นหรือโดยทำงานกับอาร์กิวเมนต์:
def f(n, s = 'foo', flux_compensator = true)
...
end
def f(*args)
case args.size
when
...
when 2
...
when 3
...
end
end
นี่ไม่ได้ตอบคำถามที่ว่าทำไม ruby ไม่มีเมธอดมากเกินไป แต่ห้องสมุดบุคคลที่สามสามารถให้บริการได้
contracts.rubyห้องสมุดช่วยให้การบรรทุกเกินพิกัด ตัวอย่างที่ดัดแปลงจากบทช่วยสอน:
class Factorial
include Contracts
Contract 1 => 1
def fact(x)
x
end
Contract Num => Num
def fact(x)
x * fact(x - 1)
end
end
# try it out
Factorial.new.fact(5) # => 120
โปรดทราบว่าสิ่งนี้มีประสิทธิภาพมากกว่าการบรรทุกเกินพิกัดของ Java เพราะคุณสามารถระบุค่าที่จะจับคู่ (เช่น1
) ไม่ใช่เพียงพิมพ์
คุณจะเห็นประสิทธิภาพลดลงโดยใช้สิ่งนี้แม้ว่า; คุณจะต้องใช้การวัดประสิทธิภาพเพื่อตัดสินใจว่าคุณสามารถทนได้เท่าไหร่
ฉันมักจะทำโครงสร้างต่อไปนี้:
def method(param)
case param
when String
method_for_String(param)
when Type1
method_for_Type1(param)
...
else
#default implementation
end
end
สิ่งนี้อนุญาตให้ผู้ใช้ของวัตถุใช้เมธอด clean_name: method ที่ชัดเจน แต่ถ้าเขาต้องการเพิ่มประสิทธิภาพการประมวลผลเขาสามารถเรียกเมธอดที่ถูกต้องได้โดยตรง
นอกจากนี้ยังทำให้การทดสอบและนักพนันดีขึ้น
มีคำตอบที่ดีอยู่แล้วว่าทำไมด้านข้างของคำถาม อย่างไรก็ตามหากใครที่กำลังมองหาวิธีแก้ไขปัญหาอื่น ๆ ก็สามารถเช็คเอาต์อัญมณีทับทิมซึ่งเป็นแรงบันดาลใจจากคุณสมบัติการจับคู่รูปแบบของ Elixir
class Foo
include Functional::PatternMatching
## Constructor Over loading
defn(:initialize) { @name = 'baz' }
defn(:initialize, _) {|name| @name = name.to_s }
## Method Overloading
defn(:greet, :male) {
puts "Hello, sir!"
}
defn(:greet, :female) {
puts "Hello, ma'am!"
}
end
foo = Foo.new or Foo.new('Bar')
foo.greet(:male) => "Hello, sir!"
foo.greet(:female) => "Hello, ma'am!"