我用一个方法扩展了String类,比如说"foo"。
class String def foo puts "Hello World." end end
为什么不能调用String.foo或String.method("foo")?当我尝试调用时,得到了 * NoMethodError *。我的最终目标是将foo传递给另一个方法,类似于bar(String.method('foo'))先谢了
String.foo
String.method("foo")
bar(String.method('foo'))
yzxexxkh1#
foo是一个示例方法,可以使用Module#instance_method获取方法,然后使用.bind(string)将其绑定到String对象,然后使用.call(args)调用该对象。
foo
.bind(string)
.call(args)
class String def foo puts "Hello #{self}." end end p String.instance_method(:foo) p String.instance_method(:foo).bind("World") String.instance_method(:foo).bind("World").call
输出:
#<UnboundMethod: String#foo() a.rb:2> #<Method: String#foo() a.rb:2> Hello World.
4jb9z9bj2#
如果你真的希望它是一个类方法,你可以使用self.methodname来定义它:
self.methodname
class String def self.foo puts "Hello" end end String.foo # => Hello
你也可以让它返回一个proc,这样它在其他地方也可以使用:
class String def self.foo = -> { puts "Hello" } end String.foo # => #<Proc:0x0000000102a05ea8 (irb):14 (lambda)> String.foo[] # => Hello
带参数:
class String def self.foo = ->(name){ puts "Hello #{name}" } end String.foo["Malte"] # => Hello Malte
monwx1rj3#
您正在定义示例方法,但尝试调用静态方法。如果调用方式正确,则该方法将按预期工作。
class String def foo puts "Hello World." end end String.new("test").foo # output: Hello World.
mkh04yzy4#
你的第一个问题是"如果我执行
为什么不能调用String.foo或String.method("foo")?当你执行
String.foo #=> NoMethodError: undefined method 'foo' for String:Class
错误消息1非常具体:类String没有方法foo。这与下面的一致。
String
String.methods.include?(:foo) #=> false
你所做的就是创建一个类string的示例方法foo,让我们以类String的示例"cat"为例:
"cat"
"cat".methods.include?(:foo) #=> true "cat".foo #=> "Hello World."
我们还可以看看
String.instance_methods #=> [:unicode_normalize, :unicode_normalize!, :ascii_only?, # :to_r,..., :foo, :count,..., :instance_exec]
或者为了更容易地在String的187个左右的示例方法中找到:foo,我们可以检查
:foo
String.instance_methods.sort #=> [:!, :!=,..., :extend, :foo, :force_encoding,..., :yield_self]
参见内核#方法和模块#示例_方法如果要在String上调用foo,则需要编写
class String def self.foo puts "Hello World." end end String.foo #=> "Hello World."
当构造方法时,self等于String,因此上式相同
self
class String def String.foo puts "Hello World." end end
通常使用self代替字面类名的原因是,它允许在不更改方法定义的情况下更改类名(我们显然不会重命名String,但我们可能希望更改用户定义的类名(例如,将Amount更改为Quantity)。实际上,Ruby只有示例方法,所以让我们看看def String.foo在示例方法方面的含义。我们看到
Amount
Quantity
def String.foo
String.class #=> Class
这意味着String是Class的一个示例。
Class
class Class def foo puts "Hello World." end end String.foo #=> "Hello World."
但这会产生不希望的效果,即使该示例方法Class对所有类都可用:
Array.foo #=> "Hello World." Hash.foo #=> "Hello World."
相反,我们希望将foo的可用性限制为仅Class的一个示例String。每个Ruby对象都有一个特殊的类,叫做"Singleton类"(Singleton类是常用的几个名称之一),我说"特殊"是因为它不同于常规类,因为它不能被子类化,也不能创建示例。我们可以编写以下代码来创建一个可以在String上调用的方法foo。
string_single = String.singleton_class #=> #<Class:String> string_single.define_method(:foo) { puts "Hello World." } #=> :foo string_single.instance_methods.include?(:foo) #=> true String.foo #=> Hello World.
参见模块#define_method。事实上
def String.foo puts "Hello World." end
只是上面使用define_method的简写。类似地,熟悉的
define_method
class String def foo puts "Hello World." end end #=> :foo
只是一个缩写
String.define_method(:foo) { puts "Hello World." } #=> :foo "cat".foo #=> "Hello World."
问题的第二部分问的是如何将一个单例方法传递给另一个单例方法。这很简单。我们已经在String的单例类上定义了foo,所以让我们定义另一个bar,它调用foo。
bar
String.singleton_class.define_method(:bar) { foo } #=> :bar String.bar #=> Hello World.
1.注意错误信息的完整性,通常它们会指出问题所在。
4条答案
按热度按时间yzxexxkh1#
foo
是一个示例方法,可以使用Module#instance_method获取方法,然后使用.bind(string)
将其绑定到String对象,然后使用.call(args)
调用该对象。输出:
4jb9z9bj2#
如果你真的希望它是一个类方法,你可以使用
self.methodname
来定义它:你也可以让它返回一个proc,这样它在其他地方也可以使用:
带参数:
monwx1rj3#
您正在定义示例方法,但尝试调用静态方法。如果调用方式正确,则该方法将按预期工作。
mkh04yzy4#
你的第一个问题是"如果我执行
为什么不能调用
String.foo
或String.method("foo")
?当你执行
错误消息1非常具体:类
String
没有方法foo
。这与下面的一致。你所做的就是创建一个类string的示例方法
foo
,让我们以类String
的示例"cat"
为例:我们还可以看看
或者为了更容易地在
String
的187个左右的示例方法中找到:foo
,我们可以检查参见内核#方法和模块#示例_方法
如果要在
String
上调用foo
,则需要编写当构造方法时,
self
等于String
,因此上式相同通常使用
self
代替字面类名的原因是,它允许在不更改方法定义的情况下更改类名(我们显然不会重命名String
,但我们可能希望更改用户定义的类名(例如,将Amount
更改为Quantity
)。实际上,Ruby只有示例方法,所以让我们看看
def String.foo
在示例方法方面的含义。我们看到
这意味着
String
是Class
的一个示例。但这会产生不希望的效果,即使该示例方法
Class
对所有类都可用:相反,我们希望将
foo
的可用性限制为仅Class
的一个示例String
。每个Ruby对象都有一个特殊的类,叫做"Singleton类"(Singleton类是常用的几个名称之一),我说"特殊"是因为它不同于常规类,因为它不能被子类化,也不能创建示例。
我们可以编写以下代码来创建一个可以在
String
上调用的方法foo
。参见模块#define_method。
事实上
只是上面使用
define_method
的简写。类似地,熟悉的只是一个缩写
问题的第二部分问的是如何将一个单例方法传递给另一个单例方法。这很简单。我们已经在
String
的单例类上定义了foo
,所以让我们定义另一个bar
,它调用foo
。1.注意错误信息的完整性,通常它们会指出问题所在。