简体   繁体   中英

Ruby's find method - argument?

I'm doing a bit of exploring. Concerning Ruby's

.find(ifnone = nil) { |obj| block }
method: from reading the documentation , it seems to me that you are supposed to be able to pass a method as an argument that will be run in the case that there are no matches for the specified conditions.

It says:

"calls ifnone and returns its result when it is specified, or returns nil otherwise."

This seems to work with any method I create that already returns nil, say:

No match.
=>nil
 No match. =>nil 

If I use a method that does return something, say:

\ndef message \n p 'No match.' \nend \n

I'll get:

 "No match." NoMethodError: undefined method `call' for "No match.":String 

Would someone be kind enough to explain to me precisely what kind of arg/method is actually supposed to be passed to the find method here? Thanks.

I'm glad you asked this question. I never thought about that argument for the find method because I never really had to use it before. I instead always ignored it until you mentioned it here.

The argument you would pass to an enumerable, like find , would be a lambda or proc. Rather than returning the default nil if no matches were found, it would return the lambda/proc.

So a quick example:

nums = [1, 2, 3, 4]
nums.find(lambda {raise ArgumentError, "No matches found"}) { |num| num == 5 }

> ArgumentError: No matches found

Also similarly, you can pass a Proc as well..

nums = [1, 2, 3, 4]
arg = Proc.new {"No matches found"}
nums.find(arg) { |num| num == 5 }

> "No matches found"

Just a quick edit, you can return any value in the lambda or proc, whether it be raising an error or returning a value. I imagine raising an error and error handling is a common use though

Edit2: Removed link to an article explaining this method. Seems the blog post has been removed :(

 NoMethodError: undefined method `call' for "No match.":String 

This is a big hint. find wants a callable object - ie something that responds to #call . Since Ruby is duck-typed, all of these will work:

def message_method
  puts "yo"
end
...find(method(:message_method)) { ... }

module MessageModule
  def self.call
    puts "yo"
  end
end
...find(MessageModule) { ... }

class MessageClass
  def call
    puts "yo"
  end
end
...find(MessageClass.new) { ... }

message_proc = Proc.new { puts "yo" }
...find(message_proc) { ... }

( lambda is another way of constructing a Proc object; the different syntax makes for a bit different semantics, but the point is lambda would work just as well.)

And a perverse example (obsolete):

require 'continuation'
callcc do |notfound|
  ...find(notfound) { ... }
  ...
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM