Gửi () làm gì trong Ruby?


94

Ai đó có thể vui lòng cho tôi biết điều gì không

send("#{Model.find...}")

là và không?


2
Đây có phải là toàn bộ dòng mã? Ý tôi là, không có gì trước khi 'gửi'?
giraff

Câu trả lời:


107

send gửi một thông báo đến một cá thể đối tượng và tổ tiên của nó trong phân cấp lớp cho đến khi một số phương thức phản ứng (vì tên của nó khớp với đối số đầu tiên).

Thực tế mà nói, những dòng đó tương đương:

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

Lưu ý rằng sendbỏ qua kiểm tra khả năng hiển thị, để bạn cũng có thể gọi các phương thức riêng tư (hữu ích cho kiểm tra đơn vị).


Nếu thực sự không có biến nào trước khi gửi, điều đó có nghĩa là Đối tượng chung được sử dụng:

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

1
Ồ, tôi hiểu rồi, vì vậy người ta có thể sử dụng send nếu muốn lưu trữ một thứ gì đó giống như 1. tháng trên cơ sở dữ liệu thay vì nói số ngày một cách tĩnh.
Christian Bankester

3
Đúng, bạn có thể sử dụng nó để gọi phương thức với các tên được tính toán, không phải tĩnh. (Bạn không nên cho phép người sử dụng không hạn chế đầu vào, tuy nhiên, để tránh gọi các phương pháp tư nhân ... Bạn có thể, tuy nhiên, cung cấp cho họ một tiền tố duy nhất: send 'user_method _' + methodname, * args)
giraff

2
Trường hợp sử dụng tốt có thể là bạn muốn kiểm tra một phương thức lớp được bảo vệ, bạn có thể gọi nó bên ngoài một lớp — trong tệp thử nghiệm ..
GN.

106

send là một phương thức ruby ​​(không có đường ray) cho phép gọi một phương thức khác theo tên.

Từ tài liệu

   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
Câu trả lời tuyệt vời, rõ ràng hơn câu trả lời được chấp nhận dài dòng.
aaron-coding

63

Một trong những tính năng hữu ích nhất mà tôi nghĩ với phương thức .send là nó có thể tự động gọi phương thức. Điều này có thể giúp bạn tiết kiệm rất nhiều công việc đánh máy. Một trong những cách sử dụng phổ biến nhất của phương thức .send là gán các thuộc tính động. Ví dụ:

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

Để chỉ định các thuộc tính thường xuyên, người ta cần

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

Hoặc sử dụng phương thức .send:

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

Nhưng tất cả có thể được thay thế bằng những thứ sau:

Giả sử ứng dụng Rails của bạn cần gán các thuộc tính cho loại xe của bạn từ thông tin người dùng nhập, bạn có thể làm

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

Cảm ơn vì liên kết tuyệt vời
sid_09

7
Sử dụng .send theo cách này làm tăng thêm độ phức tạp không cần thiết và khiến việc vô tình đưa lỗi vào mã dễ dàng hơn. Ví dụ: trong đoạn mã của bạn ở trên, nếu bạn thêm một mục nhập mới vào băm tham số của mình (chẳng hạn như 'hình trụ'), mã sẽ không thành công với lỗi phương thức không xác định.
Kevin Schwerdtfeger

1
đáp ứng? có thể được sử dụng để ngăn chặn các lỗi như vậy, nếu muốn.
Richard_G

1
Đây là lời giải thích tuyệt vời! Cảm ơn Jha!
Sharath

1
@Kevin bạn nói đúng, nhưng đôi khi điều đó có thể cần thiết. Sự linh hoạt hơn tương quan với nhiều rủi ro hơn, có thể được giảm thiểu.
Will Sheppard

12

Một ví dụ khác, tương tự như https://stackoverflow.com/a/26193804/1897857 của Antonio Jha

là nếu bạn cần đọc các thuộc tính trên một đối tượng.

Ví dụ: nếu bạn có một mảng chuỗi, nếu bạn cố gắng lặp lại chúng và gọi chúng trên đối tượng của mình, nó sẽ không hoạt động.

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

Tuy nhiên, bạn có thể sendxâu chuỗi đối tượng:

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

Cảm ơn cho lời giải thích đơn giản và dễ dàng!
Junan Chakma

Cảm ơn! Đó chính xác là câu trả lời mà tôi đang theo đuổi. Tự hỏi cái này có được sử dụng phổ biến không? Tôi đã xem qua một cái gì đó tương tự trong mã di sản, không chắc là tôi nên gắn bó với nó @ Mike Vallano.
B Liu

1
@ b-liu Tôi đã thấy nó được các nhà phát triển có kinh nghiệm sử dụng trong mã mới. Nó cũng có thể hữu ích khi sử dụng define_method: apidock.com/ruby/Module/define_method .
Mike Vallano

Tuyệt vời! Cảm ơn đống! @MikeVallano
B Liu

4

Gửi làm gì?

send là một cách gọi khác của một phương thức.

Điều này được minh họa tốt nhất bằng ví dụ:

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

Gửi các cuộc sống trong lớp Đối tượng .

Lợi ích của ths là gì?

Lợi ích của phương pháp này là bạn có thể chuyển vào phương thức bạn muốn gọi dưới dạng tham số. Đây là một ví dụ đơn giản:

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

Bạn có thể chuyển vào phương thức bạn muốn được gọi. Trong trường hợp này, chúng tôi đã vượt qua :to_s. Điều này có thể rất hữu ích khi thực hiện lập trình siêu ứng dụng ruby, bởi vì điều này cho phép chúng ta gọi các phương thức khác nhau theo các yêu cầu khác nhau của chúng ta.


0

Một trường hợp sử dụng khác cho các khung nhìn:

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

Cho phép. bạn viết chế độ xem có thể mở rộng làm việc với tất cả các loại đối tượng với:

    render 'your_view_path', object: "my_object"

Điều này thêm logic không cần thiết vào các khung nhìn và có thể có các tác động bảo mật. Đừng làm điều này. Sử dụng mảng và hàm băm.
Derrek Bertrand
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.