tôi tìm thấy mã này trong a RailsCast:Bản đồ (&: name) có ý nghĩa gì trong Ruby?
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
nào (&:name)
trong map(&:name)
nghĩa là gì?
tôi tìm thấy mã này trong a RailsCast:Bản đồ (&: name) có ý nghĩa gì trong Ruby?
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
nào (&:name)
trong map(&:name)
nghĩa là gì?
Đó là viết tắt cho tags.map(&:name.to_proc).join(' ')
Nếu foo
là một đối tượng với một phương pháp to_proc
, sau đó bạn có thể vượt qua nó đến một phương pháp như &foo
, sẽ gọi foo.to_proc
và sử dụng làm khối của phương thức.
Phương thức Symbol#to_proc
ban đầu được thêm bởi ActiveSupport nhưng đã được tích hợp vào Ruby 1.8.7. Đây là việc thực hiện:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Đây là câu trả lời hay hơn tôi. –
tags.map (: name.to_proc) là một cách viết tắt cho tags.map {| tag | tag.name} –
đây không phải là mã ruby hợp lệ, bạn vẫn cần '&', nghĩa là 'tags.map (&: name.to_proc) .join ('')' – horseyguy
Đó là viết tắt cho tags.map { |tag| tag.name }.join(' ')
Không, nó nằm trong Ruby 1.8.7 trở lên. – Chuck
Đây có phải là một thành ngữ đơn giản cho bản đồ hay Ruby luôn giải thích '&' theo một cách cụ thể? – collimarco
@Chúc cảm ơn, đã hoàn nguyên về tính chính xác. –
Đó là tương đương với
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
Một tốc ký mát mẻ, chưa được biết đến nhiều, là
array.each(&method(:foo))
mà là một viết tắt cho
array.each { |element| foo(element) }
Bằng cách gọi method(:foo)
chúng tôi mất một đối tượng Method
từ self
đại diện cho phương thức foo
và sử dụng số &
để biểu thị rằng nó có số to_proc
method chuyển đổi nó thành Proc
.
Điều này rất hữu ích khi bạn muốn làm mọi thứ điểm miễn phí kiểu. Một ví dụ là để kiểm tra xem có bất kỳ chuỗi nào trong một mảng bằng với chuỗi "foo"
hay không. Có những cách thông thường:
["bar", "baz", "foo"].any? { |str| str == "foo" }
Và có cách điểm miễn phí:
["bar", "baz", "foo"].any?(&"foo".method(:==))
Cách ưa thích nên là một dễ đọc nhất.
'array.each {| e | foo (e)} 'là ngắn hơn vẫn còn :-) +1 anyways –
@JaredBeck Yeap! Ngắn hơn nhưng không phải là điểm miễn phí :) – Gerry
Và nó là đáng ngạc nhiên nhanh chóng. –
Trong khi chúng ta cũng lưu ý rằng dấu và #to_proc
phép thuật có thể hoạt động với bất kỳ lớp nào, không chỉ là Biểu tượng. Nhiều Rubyists chọn để xác định #to_proc
trên lớp Array:
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
Ký hiệu & &
hoạt động bằng cách gửi tin nhắn trên to_proc
toán hạng của nó, trong đó, đoạn mã trên, là của lớp Array. Và kể từ khi tôi định nghĩa #to_proc
phương pháp trên Array, dòng trở thành:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send(:+, ' world!') }
Josh Lee Câu trả lời là gần như chính xác ngoại trừ các mã Ruby tương đương cần phải có được như sau.
class Symbol
def to_proc
Proc.new do |receiver|
receiver.send self
end
end
end
không
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Với mã này, khi print [[1,'a'],[2,'b'],[3,'c']].map(&:first)
được thực hiện, Ruby chia đầu vào đầu tiên [1,'a']
vào 1 và 'a' để cung cấp cho obj
1 và args*
'a' để gây ra một lỗi như Đối tượng Fixnum 1 không có phương thức tự (tức là: đầu tiên).
Khi [[1,'a'],[2,'b'],[3,'c']].map(&:first)
được thực thi;
:first
là một đối tượng Symbol, vì vậy khi &:first
được trao cho một phương pháp bản đồ như một tham số, Symbol # to_proc được gọi.
bản đồ sẽ gửi thông báo cuộc gọi đến: first.to_proc với thông số [1,'a']
, ví dụ: :first.to_proc.call([1,'a'])
được thực thi.
thủ tục to_proc trong lớp Biểu tượng gửi thông báo gửi đến đối tượng mảng ([1,'a']
) với thông số (: đầu tiên), ví dụ: [1,'a'].send(:first)
được thực thi.
lặp qua các phần tử còn lại trong đối tượng [[1,'a'],[2,'b'],[3,'c']]
.
Điều này cũng giống như thực hiện biểu thức [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
.
Câu trả lời của Josh Lee là _absolutely_ đúng, như bạn có thể thấy bằng cách suy nghĩ về '[1,2,3,4,5,6] .inject (&: +)' - inject mong đợi một lambda với hai tham số (bản ghi nhớ và mục) và ': +. to_proc' phân phối nó -' Proc.new | obj, * args | {obj.send (self, * args)} 'hoặc' {| m, o | m. + (o)} ' –
Hai điều đang diễn ra ở đây và điều quan trọng là phải hiểu cả hai.
Như được mô tả trong các câu trả lời khác, phương pháp Symbol#to_proc
đang được gọi.
Nhưng lý do to_proc
đang được gọi trên biểu tượng là vì nó được chuyển đến map
làm đối số khối. Đặt &
trước đối số trong một cuộc gọi phương thức làm cho nó được truyền theo cách này. Điều này đúng với bất kỳ phương thức Ruby nào, không chỉ là map
với các ký hiệu.
def some_method(*args, &block)
puts "args: #{args.inspect}"
puts "block: #{block.inspect}"
end
some_method(:whatever)
# args: [:whatever]
# block: nil
some_method(&:whatever)
# args: []
# block: #<Proc:0x007fd23d010da8>
some_method(&"whatever")
# TypeError: wrong argument type String (expected Proc)
# (String doesn't respond to #to_proc)
Symbol
được chuyển thành Proc
vì được chuyển thành một khối. Chúng tôi có thể hiển thị này bằng cách cố gắng để vượt qua một proc để .map
không dấu và:
arr = %w(apple banana)
reverse_upcase = proc { |i| i.reverse.upcase }
reverse_upcase.is_a?(Proc)
=> true
arr.map(reverse_upcase)
# ArgumentError: wrong number of arguments (1 for 0)
# (map expects 0 positional arguments and one block argument)
arr.map(&reverse_upcase)
=> ["ELPPA", "ANANAB"]
Mặc dù nó không cần phải được chuyển đổi, phương pháp này sẽ không biết làm thế nào để sử dụng nó bởi vì nó hy vọng một cuộc tranh luận khối . Vượt qua nó với &
cung cấp cho .map
khối dự kiến.
Đây là câu trả lời đúng nhất. Bạn giải thích cơ chế đằng sau ký hiệu và lý do tại sao chúng tôi kết thúc với một proc, mà tôi đã không nhận được cho đến khi câu trả lời của bạn. Cảm ơn bạn. – Fralcon
Nó là giống như dưới đây:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end
Đây :name
là biểu tượng thời điểm đó với phương pháp name
của đối tượng thẻ. Khi chúng tôi vượt qua &:name
đến map
, nó sẽ xử lý name
làm đối tượng proc. Đối với ngắn, tags.map(&:name)
hoạt động như:
tags.map do |tag|
tag.name
end
(&: name) là chữ viết tắt (&: name.to_proc) nó là giống như tags.map{ |t| t.name }.join(' ')
to_proc được thực sự thực hiện trong C
tags.map(&:name)
cũng giống như
tags.map{|tag| tag.name}
&:name
chỉ sử dụng biểu tượng làm tên phương thức được gọi.
Câu trả lời tôi đang tìm kiếm, thay vì đặc biệt cho procs (nhưng đó là câu hỏi của người yêu cầu) –
nó có nghĩa là
array.each(&:to_sym.to_proc)
Mặc dù chúng tôi có câu trả lời tuyệt vời rồi, nhìn qua một góc nhìn của một người mới bắt đầu tôi muốn thêm thông tin bổ sung:
gì bản đồ (&: Tên) có nghĩa là trong Ruby?
Điều này có nghĩa là bạn đang chuyển một phương thức khác làm tham số cho hàm bản đồ. (Trong thực tế bạn đang đi qua một biểu tượng được chuyển đổi thành một proc. Nhưng điều này không quan trọng trong trường hợp cụ thể này).
Điều quan trọng là bạn có method
có tên name
sẽ được phương thức bản đồ sử dụng làm đối số thay vì kiểu block
truyền thống.
Tôi đã nghe điều này được gọi là "pretzel colon", nhân tiện. –
Haha. Tôi biết điều đó như một Ampersand. Tôi chưa bao giờ nghe nó gọi là "bánh quy" nhưng điều đó có ý nghĩa. – DragonFax
Ngoài ra, bạn có thể thả các dấu ngoặc vuông 'tags.map &: name' cho mục nhập ngắn nhất thêm. – itsnikolay