为什么类方法不能与非类方法同名?

时间:2020-06-08 18:23:37

标签: ruby

我正在学习ruby,并发现无法创建名为puts的类方法:

class Printer
    def initialize(text="")
        @text = text
    end
    def puts
        puts @text
    end
end

错误是:

`puts': wrong number of arguments (given 1, expected 0)

我的期望是我可以使用如下代码:

p = Printer.new("hello")
p.puts

这不仅是因为puts是一种内置方法。例如,此代码还给出了语法错误:

def my_puts(text)
    puts text 
end

class Printer
    def initialize(text="")
        @text = text
    end
    def my_puts
        my_puts @name
    end
end

2 个答案:

答案 0 :(得分:1)

tldr ;在实例范围内,puts解析为self.puts(然后解析为本地定义的方法,而不是Kernel#puts)。这种方法覆盖 shadowing 的一种形式。

Ruby有一个'implicit self',它是这种行为的基础,并且是also how the bare puts is resolved-它来自内核,它混入每个对象中。

Object类包含Kernel模块,因此每个Ruby对象都可以使用其方法[如Kernel#puts]。这些方法在没有接收方的情况下被调用,因此可以以功能形式(例如puts进行调用,除非它们被重写)。

要在此处调用原始的同名方法,可以使用super关键字。但是,这在X#another_method 期望调用内核#puts时使用参数调用X#puts的情况下不起作用。要解决这种情况,请参见Calling method in parent class from subclass methods in Ruby(在适当的类型上使用别名或instance_method)。

class X
  def puts
    super "hello!"
  end
end

X.new.puts

P.S。第二个示例应该会失败,因为my_puts显然不带任何参数,而不会引起其他“输入”的混淆。而且,它不是语法错误,因为它是在任何语言解析后在运行时发生的。

答案 1 :(得分:1)

要添加到上一个答案(https://stackoverflow.com/a/62268877/13708583),一种解决方法是为在新puts方法中使用的原始puts创建别名。

class Printer
  alias_method :original_puts, :puts
  attr_reader :text

  def initialize(text="")
    @text = text
  end

  def puts
    original_puts text
  end
end

Printer.new("Hello World").puts

您可能对其他(静态)编程语言感到困惑,在这些语言中,您可以通过创建不同的签名来覆盖方法。

例如,这只会在Ruby中创建一个puts方法(在Java中,您将有两个puts方法(免责声明:不是Java专家)。

def puts(value)
end

def puts
end

如果您要使用其他名称相同但接受不同参数的方法,则需要使用以下可选方法参数:

def value(value = "default value")
end