9

JavaScript 欢乐时光乐土

// make a method
var happy = function(a, b, c) {
  console.log(a, b, c);
};

// store method to variable
var b = happy;

// bind a context and some arguments
b.bind(happy, 1, 2, 3);

// call the method without additional arguments
b();

输出。耶!

1 2 3

在红宝石中

# make a method
def sad a, b, c
  puts a, b, c
end

# store method to variable
b = method(:sad)

# i need some way to bind args now
# (this line is an example of what i need)
b.bind(1, 2, 3)

# call the method without passing additional args
b.call

期望的输出

1, 2, 3

对于它的价值,我知道 JavaScript 可以通过传递给的第一个参数来更改绑定的上下文.bind。在 Ruby 中,即使我无法更改上下文,我也会感到 99% 的快乐。我主要需要简单地将参数绑定到方法。

问题

有没有办法将参数绑定到 Ruby 的实例,Method这样当我在method.call没有附加参数的情况下调用时,绑定的参数仍会传递给该方法?

目标

这是一个常见的 JavaScript 习惯用法,我认为它在任何语言中都很有用。目标是将方法传递M给接收者R,其中 R 不需要(或不具有)在 R 执行该方法时向 M 发送哪些(或多少)参数的内在知识。

一个 JavaScript 演示,说明这可能是如何有用的

/* this is our receiver "R" */
var idiot = function(fn) {
  console.log("yes, master;", fn());
};


/* here's a couple method "M" examples */
var calculateSomethingDifficult = function(a, b) {
  return "the sum is " + (a + b);
};

var applyJam = function() {
  return "adding jam to " + this.name;
};

var Item = function Item(name) {
  this.name = name;
};


/* here's how we might use it */
idiot(calculateSomethingDifficult.bind(null, 1, 1));
// => yes master; the sum is 2

idiot(applyJam.bind(new Item("toast")));
// => yes master; adding jam to toast
4

2 回答 2

6

通常,重新绑定方法不是您在 Ruby 中执行的操作。相反,您使用块:

# This is our receiver "R"
def idiot(&block)
  puts("yes, master; #{block.call}")
end


# Here's a couple method "M" examples
def calculateSomethingDifficult(a, b)
  return "the sum is #{a + b}"
end

def applyJam(object)
  return "adding jam to " + object.name
end

class Item
  attr_reader :name
  def initialize(name)
    @name = name
  end
end


# Here's how we might use it
idiot do
  calculateSomethingDifficult(1, 1)
end
#=> yes master; the sum is 2

# You *can* change calling context too (see instance_exec), but I'd
# discourage it. It's probably better to just pass the object as a
# parameter.
idiot do
  applyJam(Item.new("toast"))
end
#=> yes master; adding jam to toast

如果你真的想像在 JavaScript 中那样“绑定”方法,那绝对是可能的:

class Method
  def bind *args
    Proc.new do |*more|
      self.call *(args + more)
    end
  end
end

这应该使您的示例几乎像您最初描述的那样工作:

# make a method
def sad a, b, c
  puts a, b, c
end

# store method to variable
b = method(:sad)

# Get a "bound" version of the method
b = b.bind(1, 2, 3)

# call the method without passing additional args
b.call

如果你需要它,你可以定义Object#bindable_method返回一些BindableMethod你想要的类。在大多数情况下,尽管我认为以上内容应该适合您。

于 2013-08-28T16:15:04.070 回答
4

Proc#curry在 Ruby 中类似于bind在 JavaScript 中。

def happy(a, b, c, d = 100)
  puts a, b, c, d
end

proc = method(:happy).to_proc.curry # proc is now a curried Proc

b = proc.call(1,2) # b is a curried Proc with 1 and 2 bound as the first arguments

b.call(3) # Call the proc, providing the 3rd argument

您不能完全复制您的示例代码,因为当使用必要的参数调用 curried proc 时,它会返回 proc 的结果 --- 换句话说,您不能绑定所有参数然后稍后调用 proc - - 你必须让至少一个论点不受约束。

这不一定比 Ajedi32 提供的代码更好,但我认为值得一提,因为它是 Ruby 内置的。

请参阅此处的文档:http ://ruby-doc.org/core-2.2.0/Proc.html#method-i-curry

于 2015-09-16T14:20:13.263 回答