我想用一个用户指定的块替换对象的方法的实现.在
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")
在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");
但是我怎么能在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"
我想要这样的语法:
- foo.bar do |x|
- puts "*" + x.to_s
- end
- foo.bar "baz"
我想出了以下代码
- class Foo
- def bar x = nil,&blk
- if (block_given?)
- @bar = blk
- elsif (@bar.nil?)
- puts x
- else
- @bar.call x
- end
- end
- end
但是这对于多个参数来说有点难看,但仍然感觉不对.我也可以定义一个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
所以问题是:有没有更好的方法来做到这一点,如果没有,你更喜欢什么方式
编辑:
@ welldan97的方法有效,但我松散了局部变量范围,即
- prefix = "*"
- def foo.bar x
- puts prefix + x.to_s
- end
不起作用.我想我必须坚持使用lambda才能工作?
解决方法
使用def:
- foo = Foo.new
- foo.bar "baz"
- def foo.bar x
- puts "*" + x.to_s
- end
- foo.bar "baz"
是的,那么简单
编辑:为了不松开范围,您可以使用define_singleton_method(如@freemanoid答案):
- prefix = "*"
- foo.define_singleton_method(:bar) do |x|
- puts prefix + x.to_s
- end
- foo.bar 'baz'