Ruby没有嵌套方法,对吗?那么这是什么,有更好的方法吗?

时间:2016-09-04 04:26:06

标签: ruby

我有时会使用这个结构:

class Test
  def today
    date = Date.today

    def date.is_friday?
      strftime("%A") == "Friday"
    end

    date
  end
end

它运作正常......

t = Test.new
t.today # => <Date: 2016-09-03 ((2457635j,0s,0n),+0s,2299161j)>
t.today.is_friday? # => false

我一直认为这是一种嵌套方法。但其他人坚持认为Ruby没有嵌套方法。好吧,我没有迷上这个名字。但是你怎么称呼它?是否有更好的方法来实现相同的功能?

3 个答案:

答案 0 :(得分:2)

当人们谈论嵌套方法/函数时,它们通常意味着只在封闭方法中可见/可用的东西。对于您的示例而言,这不是真的 - 一旦定义,任何人都可以在该对象上调用它。

你所展示的是Ruby的单例方法:在一个类的一个实例上定义方法的能力(例如,当人们在ruby中说类方法时,那些实际上就是该实例上的单例方法Class类)

至于是否有更好的方法,这是无法回答的,因为你还没有说出你想要解决的问题是什么。

答案 1 :(得分:1)

在方法中调用def通常是错误的方法。你想要的是定义一个封装了这个和可能的其他方法的模块,然后根据需要将它混合在任何对象上:

module DateExtensions
  def is_friday?
    wday == 5
  end
end

值得注意的是,strftime可能会返回“星期五”以外的值,因为本地化可能会生效。您可以根据自己的位置获得“Freitag”或“Vendredi”。 wday方法返回可预测的数值。

现在你可以把它混合在一起:

class Test
  def today
    date = Date.today

    date.extend(DateExtensions)

    date
  end
end

通过在模块中声明这些方法,它们更明显地是一个包的一部分。这也意味着您不需要为您创建的Date的每个实例定义一个全新的方法。

更实用的Ruby方法是定义自己的Date子类,增加这种额外的行为。

答案 2 :(得分:0)

方法定义就像任何其他代码一样是代码。它们可以像任何其他代码一样出现在方法中。就像任何其他代码一样,每次运行该方法时都会执行它们。

所以,这个

class Foo
  def foo
    def bar
    end
  end
end

不是嵌套方法,而只是定义方法的方法。通过简单地调用它两次,注意生成的警告并检查周围模块的已定义方法,很容易看出这不是嵌套方法:

foo = Foo.new

Foo.public_instance_methods(false)
#=> [:foo]

foo.foo

Foo.public_instance_methods(false)
#=> [:foo, :bar]

foo.foo
# (irb):3: warning: method redefined; discarding old bar
# (irb):3: warning: previous definition of bar was here

正如您所看到的,bar 嵌套在foo内,而是在<{em>} foo中定义 { {1}}。它仅在Foo运行后定义,并且每次foo运行时都会重新定义。

当然,您的示例有点不同,因为它不会在同一个类中覆盖该方法,而是在每次调用时将其定义在不同的类中。

请注意,有计划禁止此类用法,请参阅Feature #11665: Support nested functions for better code organization

  

但是你怎么称呼它?

这是一种定义方法的方法。

  

是否有更好的方法来实现相同的功能?

很难说出你想要达到的目的是什么。

您可以使用您的方法创建foo,并使用module创建所有对象。那将是最接近的模拟。

其他解决方案需要对代码进行更大规模的重组,例如使用Decorator Design Pattern或在您的特定Rails用例中使用Presenter。