新手问题 do ... end 和 {} 不是通用的么?

scuwolf · 2014年08月29日 · 最后由 dalang 回复于 2014年08月29日 · 2878 次阅读
class Hash
  def to_method
    hash = self
    Module.new do
      hash.each_pair do |k,v|
        define_method k.to_sym do
          v
        end
      end
    end
  end
end

class Test
  def initialize(hash)
    self.extend hash.to_method
  end
end

k = Test.new(:fun1 => 'var1')
p k.fun1

这段代码没有问题~



class Hash
  def to_method
    hash = self
    Module.new do
      hash.each_pair do |k,v|
        define_method k.to_sym { v } # 就见过这里的do end, 改成了 {}
      end
    end
  end
end

class Test
  def initialize(hash)
    self.extend hash.to_method
  end
end

k = Test.new(:fun1 => 'var1')
p k.fun1

报错

define_hash_method.v2.rb:6:in `define_method': tried to create Proc object without a block (ArgumentError)
        from define_hash_method.v2.rb:6:in `block (2 levels) in to_method'
        from define_hash_method.v2.rb:5:in `each_pair'
        from define_hash_method.v2.rb:5:in `block in to_method'
        from define_hash_method.v2.rb:4:in `initialize'
        from define_hash_method.v2.rb:4:in `new'
        from define_hash_method.v2.rb:4:in `to_method'
        from define_hash_method.v2.rb:14:in `initialize'
        from define_hash_method.v2.rb:18:in `new'
        from define_hash_method.v2.rb:18:in `<main>'

define_method(k.to_sym) { v }加个括号就好了。

#1 楼 @piecehealth

果然是的,多谢

问题在于{ v }k.to_sym比较近 所以就被认为是to_sym的 block 了,而这样define_method就没有 block 了,这显然是不可能的,你不可能定义一个没有函数体的方法。所以加对括号把{ v }的所有权给define_method

如果 ruby 智能一点,可以给出警告,而不是错误吧/

#4 楼 @sevk 优先级的问题,不算不智能。

{}的优先级更高,所以会和它前边的先结合,而do end就不会有这种情况了:

2.1.2 :002 > 1.upto 10 { |i| p i }
SyntaxError: (irb):2: syntax error, unexpected '{', expecting end-of-input
1.upto 10 { |i| p i }
           ^
2.1.2 :003 > 1.upto 10 do |i| p i end
1
2
3
4
5
6
7
8
9
10
 => 1

这跟&&优先级比and高是类似的:

2.1.2 :004 > foo = "foo" && "bar" # <=> foo = ("foo" && "bar")
 => "bar"
2.1.2 :005 > foo
 => "bar"
2.1.2 :006 > foo = "foo" and "bar" # <=> (foo = "foo") and "bar"
 => "bar"
2.1.2 :007 > foo
 => "foo"

这前看过讨论这个问题的帖子,可以参考 原来 { .. } 和 do .. end 是不一样的... 下面的讨论

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