How to implement a “callback” in Ruby?

2019-01-20 22:01发布

I'm not sure of the best idiom for C style call-backs in Ruby - or if there is something even better ( and less like C ). In C, I'd do something like:

void DoStuff( int parameter, CallbackPtr callback )
{
  // Do stuff
  ...
  // Notify we're done
  callback( status_code )
}

Whats a good Ruby equivalent? Essentially I want to call a passed in class method, when a certain condition is met within "DoStuff"

标签: ruby callback
7条回答
贼婆χ
2楼-- · 2019-01-20 22:57

This "idiomatic block" is a very core part of everyday Ruby and is covered frequently in books and tutorials. The Ruby information section provides links to useful [online] learning resources.


The idiomatic way is to use a block:

def x(z)
  yield z   # perhaps used in conjunction with #block_given?
end
x(3) {|y| y*y}  # => 9

Or perhaps converted to a Proc; here I show that the "block", converted to a Proc implicitly with &block, is just another "callable" value:

def x(z, &block)
  callback = block
  callback.call(z)
end

# look familiar?
x(4) {|y| y * y} # => 16

(Only use the above form to save the block-now-Proc for later use or in other special cases as it adds overhead and syntax noise.)

However, a lambda can be use just as easily (but this is not idiomatic):

def x(z,fn)
  fn.call(z)
end

# just use a lambda (closure)
x(5, lambda {|y| y * y}) # => 25

While the above approaches can all wrap "calling a method" as they create closures, bound Methods can also be treated as first-class callable objects:

class A
  def b(z)
    z*z
  end
end

callable = A.new.method(:b)
callable.call(6) # => 36

# and since it's just a value...
def x(z,fn)
  fn.call(z)
end
x(7, callable) # => 49

In addition, sometimes it's useful to use the #send method (in particular if a method is known by name). Here it saves an intermediate Method object that was created in the last example; Ruby is a message-passing system:

# Using A from previous
def x(z, a):
  a.__send__(:b, z)
end
x(8, A.new) # => 64

Happy coding!

查看更多
登录 后发表回答