我正在实现一个包含一个硬编码下拉列表的表单,我想知道什么是最好的解决方案,我知道两种方式都暴露在工作之下,我仍然如下:
class Example
# Options for Example.
self.options
[ 'Yes', 'No', 'Not sure' ]
end
end
由Example.options
调用,但我知道也可以这样做:
class Example
# Options for Example.
OPTIONS = [ 'Yes', 'No', 'Not sure' ]
end
将使用Example::OPTIONS
调用。
问题是,这些中的任何一种都是好方法,还是根本不重要?
答案 0 :(得分:35)
后者更好。如果它是一个方法,每次调用时都会创建一个新数组和新字符串,这会浪费资源。
答案 1 :(得分:31)
TL; DR:这取决于。这些值是否意味着在课外使用?他们会变得充满活力吗?他们可以改变子类吗?
正如@sawa所写,该方法的缺点(以这种方式编写)是每次都创建一个新的数组和字符串。
更好的写作方式是:
class Example
def self.options
@options ||= ['Yes', 'No', 'Not sure']
end
end
数组存储在实例变量@options
中,以避免每次都创建新数组。
以这种方式编写,该方法与常量非常相似。
一个关键区别是如果Example
是子类,则优化options
方法比使用常量OPTIONS
更自然:
class Parent < Example
def self.options
@options ||= [*super, 'Extra']
end
end
要做与常数类似的事情很难。想象一下,您的选项列表在类方法中使用,如下所示:
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
关于常量的棘手问题是self::OPTIONS
和OPTIONS
并不总是相同,而self.options
和options
是相同的。通常使用常量而不指定范围(例如OPTIONS
而不是self::OPTIONS
),并且继承在这种情况下根本不起作用。
请注意,该方法使您有机会在不更改API的情况下使结果动态化(即根据其他情况返回不同的结果)。
最后说明:我建议您在阵列上调用freeze
,以避免任何人修改它。
答案 2 :(得分:7)
我通常做的是混合使用上述技术:
class Player
JURISDICTIONS = %i(de uk ru)
def self.jurisdictions
JURISDICTIONS
end
end
它没什么优势:
Player.jurisdictions
而不是Player::JURISDICTIONS
)。 <强>更新强>:
可以使用private_constant
方法(http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant)
答案 3 :(得分:1)
为了进一步细化Artur的建议,我会使用类变量来隐藏常量的可见性。
class Player
@@jurisdictions = %i(de uk ru)
def self.jurisdictions
@@jurisdictions
end
end