kev*_*kev 8 ruby metaprogramming
我想用一个用户指定的块替换对象的方法的实现.在JavaScript中,这很容易实现:
function Foo() {
this.bar = function(x) { console.log(x) }
}
foo = new Foo()
foo.bar("baz")
foo.bar = function(x) { console.error(x) }
foo.bar("baz")
Run Code Online (Sandbox Code Playgroud)
在C#中它也很容易
class Foo
{
public Action<string> Bar { get; set; }
public Foo()
{
Bar = x => Console.WriteLine(x);
}
}
var foo = Foo.new();
foo.Bar("baz");
foo.Bar = x => Console.Error.WriteLine(x);
foo.Bar("baz");
Run Code Online (Sandbox Code Playgroud)
但是我怎么能在Ruby中做同样的事情呢?我有一个解决方案,将lambda存储在一个实例变量中,该方法调用lambda,但我真的不喜欢开销和语法
class Foo
def initialize
@bar = lambda {|x| puts x}
end
def bar x
@bar.call x
end
def bar= blk
@bar = blk
end
end
foo = Foo.new
foo.bar "baz"
foo.bar= lambda {|x| puts "*" + x.to_s}
foo.bar "baz"
Run Code Online (Sandbox Code Playgroud)
我想要这样的语法:
foo.bar do |x|
puts "*" + x.to_s
end
foo.bar "baz"
Run Code Online (Sandbox Code Playgroud)
我想出了以下代码
class Foo
def bar x = nil, &blk
if (block_given?)
@bar = blk
elsif (@bar.nil?)
puts x
else
@bar.call x
end
end
end
Run Code Online (Sandbox Code Playgroud)
但这对于多个参数来说有点难看,但仍然感觉不对.我也可以定义一个set_bar方法,但我也不喜欢:).
class Foo
def bar x
if (@bar.nil?)
puts x
else
@bar.call x
end
end
def set_bar &blk
@bar = blk
end
end
Run Code Online (Sandbox Code Playgroud)
所以问题是:有没有更好的方法来做到这一点,如果没有,你会选择哪种方式
编辑:@ welldan97的方法有效,但我松散了局部变量范围,即
prefix = "*"
def foo.bar x
puts prefix + x.to_s
end
Run Code Online (Sandbox Code Playgroud)
不起作用.我想我必须坚持使用lambda才能工作?
wel*_*n97 17
用途def:
foo = Foo.new
foo.bar "baz"
def foo.bar x
puts "*" + x.to_s
end
foo.bar "baz"
Run Code Online (Sandbox Code Playgroud)
是的,那很简单
编辑:不要放松你可以使用的范围define_singleton_method(如@freemanoid答案):
prefix = "*"
foo.define_singleton_method(:bar) do |x|
puts prefix + x.to_s
end
foo.bar 'baz'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9019 次 |
| 最近记录: |