Ruby 一些奇怪的 Ruby 行为

rocLv · 2022年05月19日 · 最后由 rocLv 回复于 2022年06月13日 · 1391 次阅读

最近因为给大家分享一些 Ruby 基础的内容,也有一些 Ruby 元编程的东西。然后发现了一些比较 “奇怪” 的 ruby 行为。

比如说下面这个:

class Foo
    def method_one
       def method_two
       end
    end
end

如果我们直接调用:

Foo.new. method_two 

则会报错: undefined methodmethod_two' for #Foo:0x00007fbe4ac1f5d8 (NoMethodError)`

此时我们执行:

Foo.instance_methods false

会返回:

[:method_one]

但是我们一旦执行一下:

Foo.new.method_one

这时我们再执行

Foo.instance_methods false

那么返回的就是:

[:method_one,  :method_two]

虽然行为有点怪异,不过如果按照 Ruby 设计的理念,其实也很好解释:

def 是用来定义一个实例方法,def method_one 这里在定义的时候并没有执行,method_one 必须要有一个实例调用后才会执行, 所以此时并没有method_two这个方法。

对于类方法来说也一样。

是不是挺有趣的?大家有没有其他的类似的一起分享一下?

动态语言的特性吧,在执行 method_one 之后,在运行时创建的 method_two,不知道这样理解是不是对的?

从没见过真实项目中在 def 里嵌套 def。要达到同样的意图,在 def 里写 define_method 会更合适吧

楼下说的对

def 定义方法的作用域是在 Class 里吧,所以调用 method_one 时,实际上还是在 Class 作用域下定义的 method_two。

掉进过这个坑 (基础不稳😅 )... "Ruby 元编程" p225 "属性的问题"

class MyClass
  attr_accessor :my_attr

  def initialize_attributes
    my_attr = 10
  end
end

obj = MyClass.new
obj.initialize_attributes
p obj.my_attr # nil

# not expected to be nil

# since ruby can't tell
#   if we're trying to assign value to a local variable
#   or
#   we're trying to call a "my_attr=" method

# the default behavior is "assign value to a local variable"

#### quick fix
class MyClassFix
  attr_accessor :my_attr

  def initialize_attributes
    self.my_attr = 10
  end
end

obj = MyClassFix.new
obj.initialize_attributes
p obj.my_attr # 10
class MyClass
  attr_accessor :my_attr

  def initialize_attributes
    my_attr = 10  # 局部变量
  end
end
class MyClassFix
  attr_accessor :my_attr

  def initialize_attributes
    self.my_attr = 10  # 这是方法 my_attr=
  end
end

ruby 不支持这样的嵌套方法定义, 如果开启了 warning, 会看到如下错误:

irb -w
Foo.new.method_one
Foo.new.method_one
(irb):3: warning: method redefined; discarding old method_two
(irb):3: warning: previous definition of method_two was here
quakewang 回复

这和嵌套方法定义没有关系,执行两次相当于定义了两次方法

真的够专业,够厉害!

这是因为在类里写的代码会立即执行, 但是方法定义中写的代码只会在调用方法的时候去执行, 所以 method_two 只有在调用了 method_one 以后才会存在

这很正常啊

这是当 js 的闭包在写吗?还是当 Python 的装饰器?

emmm,这看起来很正常啊。

ruby 是动态语言,声明方法只会注册,真正执行的时候才会运行。

函数内返回函数,也是一个支持函数范式的特性。可以建立起函数式编程。py、js 里也是可以。

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