Ruby 一些奇怪的 Ruby 行为

rocLv · May 19, 2022 · Last by rocLv replied at June 13, 2022 · 1605 hits

最近因为给大家分享一些 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
Reply to quakewang

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

真的够专业,够厉害!

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

这很正常啊

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

emmm,这看起来很正常啊。

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

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

Reply to Mark24

You need to Sign in before reply, if you don't have an account, please Sign up first.