How to implement a “callback” in Ruby?

后端 未结 7 1327
臣服心动
臣服心动 2020-12-12 10:00

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:

voi         


        
相关标签:
7条回答
  • 2020-12-12 10:39

    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!

    0 讨论(0)
提交回复
热议问题