Ruby 中的 + 方法到底做了什么?
What does the + method in Ruby do, exactly?
假设我想编写自己的数学运算符,如“+”
简单版本为:
def plus(a,b)
return a+b
end
但这不是真正的“+”所做的。
我要3.add(4) # =>7
但是我如何告诉 ruby 获取我使用我的方法的对象?
我试过了
def add(c)
return self+c
end
但我收到错误消息:
:in <main>': private method
add' 要求 3:Fixnum (NoMethodError)
ruby 中的加号 (+) 可以像任何其他方法一样被覆盖(您可以查找运算符重载):
class MyOperator
attr_accessor :text
def initialize(text)
@text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
所以它并没有什么神奇之处。但是如果重载运算符在您的上下文中有意义,您必须小心。
问题
您定义了方法:
def add(c)
return self + c
end
并试图这样使用它:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
了解此错误消息
此错误消息准确地告诉您问题出在哪里。我认为您的问题只是您不了解 Ruby 如何在对象上调用方法。
当Ruby看到3.add(4)
时,它首先查看接收器、3
,并确定:
3.class #=> Fixnum
这告诉它定义方法 add
的位置:在 class Fixnum
中或在 Fixnum
的祖先的 class 中或模块。
所以它在那里寻找它,没有找到它,并发出一条错误消息。我们可以确认它不存在:
Fixnum.instance_methods.include?(:add)
#=> false
那么add
是在哪里定义的呢?
虽然你确实定义了它,但它在哪里?让我们找出答案:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods
returns 是在 Object
和 [=35= 上定义的所有 public 实例方法的数组]的祖先。 add
不在其中,因此我们得出结论 add
是 protected 或 private 方法:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
让我们尝试在 Object
:
的实例上调用该方法
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
考虑到 Object#add
是私有的,这是有道理的。但是,我们可以使用 Object#send:
调用私有方法
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
作为练习,请确保您了解 Ruby 采取的导致她引发此异常的步骤(实例方法 +
未在 Object
上定义,或等效, Object
的实例没有方法 +
).
对了,你是在哪里定义add
的?我的意思是,当您定义 self
时,它的值是多少?让我们看看:
self #=> main
self.class #=> Object
我们看到 add
必须定义在 class 上,它的接收者是一个实例。 (一口,是的,但这很重要,因此请确保您理解这一点)。
为什么 Object#add
是私有的而不是 public?
考虑:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
这是因为 A
从 Object
继承了 greet
:
A.ancestors.include?(Object) #=> true
如果 Object#greet
是 public,每个内置 class 和您定义的每个 class 都会有一个 public 实例方法 greet
.那将导致极大的痛苦。 (假设您有一个方法 great
并且输入错误 greet
!)即使是私有 greet
也会造成麻烦。)
add
应该定义在哪里?
由于add.class => Fixnum
,我们这样定义它:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
如果我在 class Fixnum
之后包含 puts "self#{self}"
行,它会打印 "Fixnum"。使用显示 self
值的 puts
语句对代码进行加盐通常有助于理解正在发生的事情。
最后一件事:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
为什么这个没有returnFixnum
?由于 method
没有明确的接收者(即没有 xx.method
),Ruby 假设接收者是 self
,这里是:
self #=> main
所以她在 self.class => Object
中寻找方法 method
,你知道她找到了什么(或者,我应该说,没有找到)。相反,我们需要写:
Fixnum.instance_method(:add).owner #=> Fixnum
或
3.method(:add).owner #=> Fixnum
这里的3
当然可以替换为Fixnum
.
的任意实例
注意我已经稍微简化了这个解释。在搜索方法时,Ruby 还会查看接收者的单例 class。这对于直接对象(数字、符号、true
、false
和 nil
)不是问题,但是,因为它们没有单例 classes:
3.singleton_class #=> TypeError: can't define singleton
对比,例如:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>
假设我想编写自己的数学运算符,如“+”
简单版本为:
def plus(a,b)
return a+b
end
但这不是真正的“+”所做的。
我要3.add(4) # =>7
但是我如何告诉 ruby 获取我使用我的方法的对象?
我试过了
def add(c)
return self+c
end
但我收到错误消息:
:in <main>': private method
add' 要求 3:Fixnum (NoMethodError)
ruby 中的加号 (+) 可以像任何其他方法一样被覆盖(您可以查找运算符重载):
class MyOperator
attr_accessor :text
def initialize(text)
@text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
所以它并没有什么神奇之处。但是如果重载运算符在您的上下文中有意义,您必须小心。
问题
您定义了方法:
def add(c)
return self + c
end
并试图这样使用它:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
了解此错误消息
此错误消息准确地告诉您问题出在哪里。我认为您的问题只是您不了解 Ruby 如何在对象上调用方法。
当Ruby看到3.add(4)
时,它首先查看接收器、3
,并确定:
3.class #=> Fixnum
这告诉它定义方法 add
的位置:在 class Fixnum
中或在 Fixnum
的祖先的 class 中或模块。
所以它在那里寻找它,没有找到它,并发出一条错误消息。我们可以确认它不存在:
Fixnum.instance_methods.include?(:add)
#=> false
那么add
是在哪里定义的呢?
虽然你确实定义了它,但它在哪里?让我们找出答案:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods
returns 是在 Object
和 [=35= 上定义的所有 public 实例方法的数组]的祖先。 add
不在其中,因此我们得出结论 add
是 protected 或 private 方法:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
让我们尝试在 Object
:
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
考虑到 Object#add
是私有的,这是有道理的。但是,我们可以使用 Object#send:
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
作为练习,请确保您了解 Ruby 采取的导致她引发此异常的步骤(实例方法 +
未在 Object
上定义,或等效, Object
的实例没有方法 +
).
对了,你是在哪里定义add
的?我的意思是,当您定义 self
时,它的值是多少?让我们看看:
self #=> main
self.class #=> Object
我们看到 add
必须定义在 class 上,它的接收者是一个实例。 (一口,是的,但这很重要,因此请确保您理解这一点)。
为什么 Object#add
是私有的而不是 public?
考虑:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
这是因为 A
从 Object
继承了 greet
:
A.ancestors.include?(Object) #=> true
如果 Object#greet
是 public,每个内置 class 和您定义的每个 class 都会有一个 public 实例方法 greet
.那将导致极大的痛苦。 (假设您有一个方法 great
并且输入错误 greet
!)即使是私有 greet
也会造成麻烦。)
add
应该定义在哪里?
由于add.class => Fixnum
,我们这样定义它:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
如果我在 class Fixnum
之后包含 puts "self#{self}"
行,它会打印 "Fixnum"。使用显示 self
值的 puts
语句对代码进行加盐通常有助于理解正在发生的事情。
最后一件事:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
为什么这个没有returnFixnum
?由于 method
没有明确的接收者(即没有 xx.method
),Ruby 假设接收者是 self
,这里是:
self #=> main
所以她在 self.class => Object
中寻找方法 method
,你知道她找到了什么(或者,我应该说,没有找到)。相反,我们需要写:
Fixnum.instance_method(:add).owner #=> Fixnum
或
3.method(:add).owner #=> Fixnum
这里的3
当然可以替换为Fixnum
.
注意我已经稍微简化了这个解释。在搜索方法时,Ruby 还会查看接收者的单例 class。这对于直接对象(数字、符号、true
、false
和 nil
)不是问题,但是,因为它们没有单例 classes:
3.singleton_class #=> TypeError: can't define singleton
对比,例如:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>