新手问题 define_method 调用 yield 报错

tablecell · 2024年07月03日 · 最后由 Sebastiankoelpin 回复于 2024年07月15日 · 477 次阅读

test.rb

def test1(  &block)
#  puts   block
#  block.call
  yield

end

define_method(:test2) { | &block|
#  puts  block
#  block.call
  yield  #if block_given?
}

test1 {
 puts "test1"
}
test2 {
 puts "test2"
}

用字面量定义正常调用 yield,同样的代码换成 define_method 就报错 而且不同版本报错不一样

ruby27 以上报错 Invalid yield (SyntaxError)

ruby27 以下报错 no block given (yield) (LocalJumpError) 但是 test2 明明传了 block 的

你可以理解为

def test1(&block)
  yield
end

yield 是个关键字,出现在这样的语法中,会被解析。

def  <FuncName> 
   yield
end

而第二个例子 define_method 传入的是一个 block 参数,而 block 参数不是一个函数结构,所以没有 yield。

define_method(:test2) { | &block|
  yield  #if block_given?
}

这里你可以用 block.call 实现 yield 效果。

define_method(:test2) { | &block|
  block.call
}

def 会打开一个新的作用域, def 内部 yeild 可以执行这个闭包的 block

但是 define_method 不会打开作用域, define_method 内部和外部是同一个作用域,所以 yield 执行的是上层作用域的代码

def make_method
  define_method(:hello) { yield }
end

make_method
hello { puts "hi" } #=> LocalJumpError: no block given

make_method { puts "make_method block" }
hello { puts "hi" } #=> "make_method block"

lyb124553153 回复

e, 用 singleton 来说明 define_method, 只有魔法能打败魔法

需要 登录 后方可回复, 如果你还没有账号请 注册新账号