【问题标题】:In Ruby, why does `Array.length` give NoMethodError?在 Ruby 中,为什么 `Array.length` 会给出 NoMethodError?
【发布时间】:2017-10-03 02:59:40
【问题描述】:

在 Python 中,我可以通过调用 __len__ 方法来获取 list 的长度。 __len__ 不是在每个单独的 list 对象上定义的,而是在 list 类上定义的。可以通过类直接访问方法:

>>> [].__len__()
0
>>> type([])
<class 'list'>
>>> list.__len__([])
0

但是,等效代码在 Ruby 中不起作用:

> [].length
=> 0
> [].class
=> Array
> Array.length([])
NoMethodError: undefined method `length' for Array:Class

为什么使用Array.length时找不到length方法? Ruby 中的方法查找与 Python 的工作方式不同吗?

【问题讨论】:

    标签: python ruby nomethoderror name-lookup


    【解决方案1】:

    是的,Ruby 中的方法查找与 Python 中的方法查找有很大不同。

    TL;DR 的答案是,如果您真的想从 Array 类对象中提取 length 方法,则需要编写 Array.instance_method(:length)。这将为您提供一个 UnboundMethod 对象,然后您可以将其绑定到特定对象并调用:

    unbound_method = Array.instance_method(:length)
    ary = [1,2,3,4]
    bound_method = unbound_method.bind(ary)
    bound_method.call #=> 4
    

    不出所料,这在 Ruby 中并不常见。

    在 Ruby 中,类本身就是对象,是类Class 的实例;这些类有自己的方法,超出了它们为其实例提供的方法,例如newnamesuperclass 等方法。当然,可能Array 类对象上定义一个length 方法,以便您可以编写Array.length,但这与同名的实例方法没有内在关联。在核心类和标准库中有几个地方实际上是这样做的,但在大多数情况下,这在 Ruby 中并不惯用。

    Class 对象直接响应的方法与其为其实例提供的方法之间的区别可以在methodsinstance_methods 方法的输出中清楚地看到:

    irb(main):001:0> Array.methods
    => [:[], :try_convert, :new, :allocate, :superclass, ...
    irb(main):002:0> Array.instance_methods
    => [:each_index, :join, :rotate, :rotate!, :sort!, ...
    

    Ruby 中的方法查找不像 Python 那样工作的一个原因是,类和实例可能需要以不同的方式响应某些方法名称。例如,考虑一个假设的 Person 类:

    Person.ancestors # => [Person, Animal, Organism, Object, Kernel, BasicObject]
    john = Person.new(...)
    john.ancestors # => [John Sr., Sally, Jospeh, Mary, Charles, Jessica]
    

    当然,在 Python 中,第一次调用会出错:如果不将 Person 的实例传递为 __self__,就不能调用 Person.ancestors,这没有任何意义。但是那么你如何获得 Person 类的祖先呢?你会将Person 本身传递给一个函数:inspect.getmro(Person)。这在 Python 中是惯用的,但在 Ruby 中会被认为是极差的风格。

    本质上,作为不同的语言,尽管它们在许多方面相似,但它们在解决某些问题时仍然有不同的方法,并且一些被认为是好的做法或风格的东西在另一种中非常糟糕(反之亦然)反之亦然)。

    【讨论】:

      猜你喜欢
      • 2014-10-18
      • 1970-01-01
      • 1970-01-01
      • 2016-03-02
      • 2012-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多