send () ทำอะไรใน Ruby?


คำตอบ:


111

send ส่งข้อความไปยังอินสแตนซ์อ็อบเจ็กต์และบรรพบุรุษของมันในลำดับชั้นของคลาสจนกว่าเมธอดบางอย่างจะตอบสนอง (เนื่องจากชื่อตรงกับอาร์กิวเมนต์แรก)

ในทางปฏิบัติบรรทัดเหล่านี้เทียบเท่า:

1.send '+', 2
1.+(2)
1 + 2

โปรดทราบว่าsendข้ามการตรวจสอบการมองเห็นเพื่อให้คุณสามารถเรียกใช้เมธอดส่วนตัวได้เช่นกัน (มีประโยชน์สำหรับการทดสอบหน่วย)


หากไม่มีตัวแปรก่อนส่งนั่นหมายความว่า global Object ถูกใช้:

send :to_s    # "main"
send :class   # Object

1
โอ้ฉันเห็นดังนั้นอาจใช้การส่งหากต้องการจัดเก็บบางอย่างเช่น 1. เดือนบนฐานข้อมูลแทนที่จะบอกจำนวนวันแบบคงที่
Christian Bankester

3
จริงอยู่คุณสามารถใช้มันเพื่อเรียกเมธอดด้วยชื่อที่คำนวณไม่ใช่แบบคงที่ (คุณไม่ควรอนุญาตการป้อนข้อมูลของผู้ใช้ที่ไม่ จำกัด เพื่อหลีกเลี่ยงการเรียกใช้เมธอดส่วนตัว ... อย่างไรก็ตามคุณสามารถให้คำนำหน้าเฉพาะแก่พวกเขาได้: ส่ง 'user_method _' + methodname, * args)
giraff

2
กรณีการใช้งานที่ดีอาจเป็นไปได้ว่าคุณต้องการทดสอบเมธอดคลาสที่มีการป้องกันคุณสามารถเรียกมันว่านอกคลาส - ในไฟล์ทดสอบ ..
GN

108

ส่งเป็นวิธีการทับทิม (ไม่มีราง) ที่อนุญาตให้เรียกใช้วิธีอื่นโดยใช้ชื่อ

จากเอกสารประกอบ

   class Klass
     def hello(*args)
       "Hello " + args.join(' ')
     end
   end
   k = Klass.new
   k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"

http://corelib.rubyonrails.org/classes/Object.html#M001077


5
คำตอบที่ดีชัดเจนกว่าคำตอบที่ยอมรับโดยละเอียด
aaron-coding

66

หนึ่งในคุณสมบัติที่มีประโยชน์ที่สุดที่ฉันคิดด้วยวิธีการ. ส่งคือมันสามารถเรียกใช้เมธอดแบบไดนามิกได้ วิธีนี้ช่วยให้คุณประหยัดเวลาพิมพ์ได้มาก วิธีการหนึ่งที่นิยมใช้มากที่สุดคือการกำหนดแอตทริบิวต์แบบไดนามิก ตัวอย่างเช่น:

class Car
  attr_accessor :make, :model, :year
end  

ในการกำหนดแอตทริบิวต์อย่างสม่ำเสมอจำเป็นต้องมี

c = Car.new
c.make="Honda"
c.model="CRV"
c.year="2014"

หรือใช้วิธีการ. ส่ง:

c.send("make=", "Honda")
c.send("model=", "CRV")
c.send("year=","2014")

แต่ทั้งหมดนี้สามารถแทนที่ได้ด้วยสิ่งต่อไปนี้:

สมมติว่าแอป Rails ของคุณต้องกำหนดแอตทริบิวต์ให้กับคลาสรถของคุณจากการป้อนข้อมูลของผู้ใช้คุณสามารถทำได้

c = Car.new()
params.each do |key, value|
  c.send("#{key}=", value)
end

ขอบคุณสำหรับลิงค์ที่ดี
sid_09

7
การใช้. ส่งในลักษณะนี้จะเพิ่มความซับซ้อนที่ไม่จำเป็นและทำให้ง่ายต่อการแนะนำจุดบกพร่องในโค้ด ตัวอย่างเช่นในโค้ดของคุณด้านบนหากคุณเพิ่มรายการใหม่ในแฮชพารามิเตอร์ของคุณ (เช่น 'กระบอกสูบ') โค้ดจะล้มเหลวโดยมีข้อผิดพลาดของวิธีการที่ไม่ได้กำหนด
Kevin Schwerdtfeger

1
ตอบสนองต่อการ? สามารถใช้เพื่อป้องกันข้อผิดพลาดดังกล่าวหากต้องการ
Richard_G

1
นี่เป็นคำอธิบายที่ยอดเยี่ยม! ขอบคุณ Jha!
Sharath

1
@ เควินคุณพูดถูก แต่บางครั้งก็อาจจำเป็น ความยืดหยุ่นที่มากขึ้นสัมพันธ์กับความเสี่ยงที่มากขึ้นซึ่งสามารถบรรเทาได้
Will Sheppard

13

อีกตัวอย่างหนึ่งที่คล้ายกับhttps://stackoverflow.com/a/26193804/1897857ของ Antonio Jha

คือถ้าคุณต้องการอ่านแอตทริบิวต์บนวัตถุ

ตัวอย่างเช่นหากคุณมีอาร์เรย์ของสตริงหากคุณพยายามวนซ้ำและเรียกสตริงเหล่านั้นบนอ็อบเจ็กต์ของคุณจะไม่ทำงาน

atts = ['name', 'description']
@project = Project.first
atts.each do |a|
  puts @project.a
end
# => NoMethodError: undefined method `a'

อย่างไรก็ตามคุณสามารถsendกำหนดสตริงให้กับวัตถุ:

atts = ['name', 'description']
@project = Project.first
atts.each do |a|
  puts @project.send(a)
end
# => Vandalay Project
# => A very important project

ขอบคุณสำหรับคำอธิบายที่ง่ายและสะดวก!
Junan Chakma

ขอบคุณ! นั่นคือคำตอบที่ฉันต้องการ สงสัยจะใช้กันทั่วไป? ฉันเจอบางอย่างที่คล้ายกันในรหัสเดิมไม่แน่ใจว่าควรติดไว้ @ Mike Vallano
B Liu

1
@ b-liu ฉันเคยเห็นมันใช้โดยนักพัฒนาที่มีประสบการณ์ในโค้ดใหม่ นอกจากนี้ยังจะมีประโยชน์เมื่อใช้define_method: apidock.com/ruby/Module/define_method
Mike Vallano

สุดยอด! ขอบคุณกอง! @MikeVallano
B Liu

5

ส่งไปทำอะไร?

send เป็นอีกวิธีหนึ่งในการเรียกเมธอด

ตัวอย่างนี้แสดงได้ดีที่สุด:

o = Object.new
o.send(:to_s) # => "#<Object:0x00005614d7a24fa3>"
# is equivalent to:
o.to_s # => "#<Object:0x00005614d7a24fa3>"

ส่งอาศัยอยู่ในระดับวัตถุ

ประโยชน์ของ ths คืออะไร?

ประโยชน์ของวิธีนี้คือคุณสามารถส่งผ่านเมธอดที่คุณต้องการเรียกเป็นพารามิเตอร์ได้ นี่คือตัวอย่างง่ายๆ:

def dynamically_call_a_method(name)
    o = Object.new
    o.send name 
end
dynamically_call_a_method(:to_s) # => "#<Object:0x00005614d7a24fa3>"

คุณสามารถส่งผ่านวิธีการที่คุณต้องการให้เรียก :to_sในกรณีนี้เราผ่านใน สิ่งนี้มีประโยชน์มากในการทำโปรแกรม Ruby เพราะทำให้เราสามารถเรียกวิธีการต่างๆตามข้อกำหนดที่แตกต่างกันของเราได้


0

กรณีการใช้งานอื่นสำหรับมุมมอง:

    <%= link_to 
    send("first_part_of_path_#{some_dynamic_parameters}_end_path", 
    attr1, attr2), ....
    %>

อนุญาต คุณสามารถเขียนมุมมองที่ปรับขนาดได้ซึ่งทำงานกับวัตถุทุกประเภทด้วย:

    render 'your_view_path', object: "my_object"

สิ่งนี้เพิ่มตรรกะที่ไม่จำเป็นให้กับมุมมองและอาจมีผลกระทบด้านความปลอดภัย อย่าทำอย่างนี้ ใช้อาร์เรย์และแฮช
Derrek Bertrand
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.