Ruby中的方法:对象还是没有对象?

受此讨论的启发,经过一番谷歌搜索之后,我无法找到有关Ruby中方法的一个非常简单的问题的答案:方法对象是否存在?

到处都有不同的观点,我真的很想听听深入的解释。

我知道Object#method方法,该方法采用方法名称并返回Method实例,但是另一方面,您可以对块执行类似的操作,以使其成为Proc实例,并且块不是对象,因此 是什么使方法有所不同?

6个解决方案
61 votes

方法是 Ruby的语法,但它们不是值 Ruby程序可以在上面运行的代码。 也就是说,Ruby的方法不是 串起来的方式 数字和数组。 它是 但是,有可能获得一种方法 代表给定方法的对象, 我们可以间接调用方法 通过Method对象。

从Ruby编程语言:
alt text

JRL answered 2020-07-25T23:00:23Z
18 votes

你真的不能说。

获取方法的唯一方法是将File.new消息发送给某个对象,该对象随后将返回Proc.new对象。 但是proc是该方法本身的对象吗? 还是该方法的包装? 还是它是原始方法的转换版本?

您可能不知道:如果要查看方法,则必须调用File.new,这时您肯定会得到一个对象。 在您致电Proc.new之前,您看不到它,因此无法分辨。

几个数据点:在Ruby中,所有东西都返回一个值。 File.new返回什么? 它总是返回Proc.new,而不是proc对象。 还有Proc.new? 它返回&,但不返回Method(也不返回UnboundMethod)。 [注意:在Rubinius中,def返回该方法的已编译字节码,但仍不返回Method对象。

如果查看Ruby语言规范6.1节的第4段和第5段(第5和6页的第29-34和1-5行),您可以清楚地看到方法和对象之间存在区别。 并且,如果您查看内置类的规范,您将发现既没有File.new也没有Proc.new,也没有proc。IOW:您可以构建一个完全符合标准的Ruby解释器,其中方法不是对象。

现在,块OTOH绝对不是对象。 有多种方法可以从块构造File.new对象,然后这些对象具有与原始块相同的行为(Proc.newprocProc.new&标记),但块本身不是对象。

可以这样考虑:您可以将字符串传递给File.new来构造文件对象,但这不会使字符串成为文件。 您可以将一个块传递给Proc.new来构造proc对象,但这并不能使一个块成为proc。

Jörg W Mittag answered 2020-07-25T23:01:11Z
11 votes

在Ruby中,方法和块本身并不是本机或一流对象。 但是,它们可以很容易地包裹在物体中,因此通常没有什么区别。

但是请尝试一下,并牢记以下结果:

a = Object.method(:new).object_id
b = Object.method(:new).object_id
a == b
=> false

在Haskell中,所有值(包括数字以及lambda和函数)都是一等值。 在语言的每个方面,它们都被等同地对待。 在Ruby中不是这种情况,但是可以近似。

yfeldblum answered 2020-07-25T23:01:41Z
2 votes

即使方法的返回值是对象而不是nil,对象和方法也不相同。除非在方法,lambda或proc范围内,否则对象将驻留在堆中,并且该方法本身位于堆栈中,并且在解释后具有分配的地址,而将静态对象和类对象分配在堆上。 Ruby仍然使用C来解释它,并将其传递给VALUE结构。

bvrwoo_3376 answered 2020-07-25T23:02:01Z
0 votes

因为括号在ruby中是可选的,所以在需要通过method方法显式提取方法对象的意义上,方法对象通常是“隐藏的”。 但是,如果您努力捕获一个方法对象,就会很清楚它的行为就像一个对象。 由于Ruby> = 2.1,因此比以往更容易利用。

例如,您可以使方法的行为更像在Javascript中一样(其中没有parens是方法对象,而parens是用于调用该方法的),如下所示:

foo = method def foo
  def a(num)
    3 * num.to_i
  end

  n = yield if block_given?
  a(n || 3)
rescue
  "oops!"
end

def foo.bar(num)
  a(num)
end

foo.class #=> Method
foo() #=> 9
foo.call #=> 9
foo.call{2} #=> 6
foo(){2} #=> 6
foo.call{ raise "blam!" } #=> "oops!"
foo.bar(5) #=> 15

有关将这些示例编写为测试的版本,请参见此要点。

JRL的答案引用了Matz的书,他说方法不是像字符串之类的对象,而是真正的方法对象,除了parens / no-parens之外,它们的行为与其他任何ruby对象都非常相似。 这是一种鸭子式的语言,因此我想将方法限定为本书中的对象。

Andrew answered 2020-07-25T23:02:35Z
0 votes

在Ruby中,方法不是对象。 这是令人困惑的,因为有一个Method类,并且您可以获得Method的实例。 这些实例只是方法本身的代理。 这些实例提供了一些有用的功能。 它们具有一些内部魔术,可以将其与实际方法联系起来(因此您可以执行Method#call之类的操作),但实际上无法访问该东西(AFAIK)。

1.method(:to_s).object_id == 1.method(:to_s).object_id #=> false

这意味着1具有两个#to_s方法(不是),或者#method方法返回的实际上不是方法本身,而是该方法的某种代理。 如果方法实际上是对象,那么您将有可能两次获得相同的实例。 如果方法是对象,那么您将能够进行操作,例如在它们上设置实例变量,然后在第二次检索方法对象后获得该实例变量的值。 你不能那样做。 因此,尽管通常没有什么区别,但在某些情况下我发现自己无法做自己想做的事情。

1.method(:to_s).instance_variable_set(:@foo, 'foo') #=> "foo" 
1.method(:to_s).instance_variable_get(:@foo)        #=> nil 
# And just in case you question it...
1.object_id == 1.object_id                          #=> true 
Huliax answered 2020-07-25T23:03:01Z
translate from https://stackoverflow.com:/questions/2602340/methods-in-ruby-objects-or-not