Ruby on rails Ruby/Rails中的类方法与常量

Ruby on rails Ruby/Rails中的类方法与常量,ruby-on-rails,ruby,Ruby On Rails,Ruby,我正在实现一个表单,其中包含一个集合的硬编码下拉列表,我想知道什么是最好的解决方案,我知道下面工作中暴露的两种方法,但我还是做了如下工作: class Example # Options for Example. self.options [ 'Yes', 'No', 'Not sure' ] end end 由示例.options调用,但我知道也可以执行以下操作: class Example # Options for Example. OPTIONS = [

我正在实现一个表单,其中包含一个集合的硬编码下拉列表,我想知道什么是最好的解决方案,我知道下面工作中暴露的两种方法,但我还是做了如下工作:

class Example

  # Options for Example.
  self.options
    [ 'Yes', 'No', 'Not sure' ]
  end
end
示例.options
调用,但我知道也可以执行以下操作:

class Example

  # Options for Example.
  OPTIONS = [ 'Yes', 'No', 'Not sure' ]
end
这将通过
Example::OPTIONS
调用


问题是,这些方法是好的还是根本不重要?

后者更好。如果它是一个方法,每次调用它时都会创建一个新数组和新字符串,这是对资源的浪费;医生:这要看情况。这些值是否要在类外使用?他们会变得充满活力吗?它们是否可以更改为子类

正如@sawa所写,该方法(以这种方式编写)的缺点是每次都会创建一个新的数组和字符串

更好的写作方法是:

class Example
  def self.options
    @options ||= ['Yes', 'No', 'Not sure']
  end
end
数组存储在实例变量
@options
中,以避免每次创建新数组

以这种方式编写的方法与常量非常相似

class Player
  @@jurisdictions = %i(de uk ru)

  def self.jurisdictions
    @@jurisdictions
  end
end
一个关键区别是,如果将
示例
子类化,则与常量
选项
相比,细化
选项
方法更为自然:

class Parent < Example
  def self.options
    @options ||= [*super, 'Extra']
  end
end
class父类<示例
def self.options
@选项| |=[*超级,“额外”]
结束
结束
用常数做类似的事情是困难的。假设您的选项列表用于类方法,如下所示:

class Example
  OPTIONS = ['Yes', 'No', 'Not sure']

  def self.foo(arg)
     puts "Available options:",
          self::OPTIONS  # The self:: is needed here
     # ...
  end
end

class Parent < Example
  OPTIONS = [*superclass::OPTIONS, 'Extra']
end
类示例
选项=[“是”、“否”、“不确定”]
def self.foo(arg)
将“可用选项:”,
self::OPTIONS#这里需要self::
# ...
结束
结束
类父类<示例
选项=[*超类::选项,“额外”]
结束
常数的棘手之处在于
self::OPTIONS
OPTIONS
并不总是相同的,而
self.OPTIONS
OPTIONS
是相同的。常量通常在不指定范围的情况下使用(例如,
OPTIONS
而不是
self::OPTIONS
),在这种情况下继承将不起作用

请注意,该方法使您有机会在不更改API的情况下动态生成结果(即根据其他情况返回不同的结果)


最后一点注意:我建议在您的阵列上调用
freeze
,以避免任何人对其进行修改。

我通常会混合使用上述技术:

class Player
  JURISDICTIONS = %i(de uk ru)

  def self.jurisdictions
    JURISDICTIONS
  end
end
它没有什么优势:

  • 它提供了一个干净的接口,封装了一个常量(您调用
    Player.辖区
    而不是
    Player::辖区
  • 以后只需改变方法,就可以添加额外的逻辑
  • 该方法可在试验中使用
嗯,这里的表现并不重要

更新
可以使用
private\u Constant
method()

隐藏常量为了进一步完善Artur的建议,我将使用一个类变量来隐藏常量的可见性

class Player
  @@jurisdictions = %i(de uk ru)

  def self.jurisdictions
    @@jurisdictions
  end
end

普遍接受的方法是后一种方法,因为注释是向用户提供的一种文档形式,这与可能的答案有关,我建议在字符串上使用符号,除非您的代码特别需要字符串。因此,
[:是,:否,:不确定]
@CharlesCaldwell或更短的
%i[是否不确定]
。在我看来,这个问题与哪个更好地解释选项背后的心态有关。常量包含源代码中定义的常量值,变量包含变化的值,方法应该做些什么(而不是返回硬编码数组)。太棒了,+10,如果可以;-)+1同时调用
示例。当您知道是一个类常量时,方法将告诉options是一个方法。这是生成一致代码的另一个技巧。不过,在方法中缓存数组很容易
@options | |=[…]
写了另一个答案,因为我不同意常数是更好的方法。方法提供的灵活性比节省一分钱更重要(显然,IMHO),你仍然可以对常数做类似的事情:
示例::options=[“是”、“否”、“不确定”];父项::选项=[*示例::选项,“额外”]
。唯一的区别是您必须显式地编写父类,而不是使用
super
@sawa:的确,您可以(并且您可以使用
superclass
而不是显式地编写父类),但是访问常量可能会很棘手。编辑了我的答案。问题中的相关想法是直接调用常量,如
Example::OPTIONS
Parent::OPTIONS
,或
OPTIONS
。我不明白你为什么要定义
self.foo
来调用它们。这是一个使用
options/options
的类方法示例。你有一个拼写错误,它应该是self。效果更好,同意!但到目前为止,我无法解决这里所描述的继承问题:在我写了这个之后,我发现你也应该考虑类级别的实例变量: