【问题标题】:Prefer %w(...) to a literal array? [closed]更喜欢 %w(...) 到文字数组? [关闭]
【发布时间】:2012-10-13 20:04:22
【问题描述】:

在 RubyMine 中输入一个简单的字符串文字数组时:

cols =
[
  "Col1",
  "Col2"
]

RubyMine 抱怨说我应该更喜欢使用 %w 而不是文字数组:

cols = %w(Col1 Col2)

它提供了一个指向 Ruby 样式指南 (here) 的链接,其中说:

当你需要一个数组时,首选 %w 而不是文字数组语法 字符串。

# bad
STATES = ['draft', 'open', 'closed']

# good
STATES = %w(draft open closed)

我可以看到%w 如何提供更简洁的代码。除了简洁之外,还有什么理由更喜欢一种方法而不是另一种?

【问题讨论】:

  • 好吧,链接的指南非常固执己见,我认为人们实际上不会遵循所描述的每一条规则。我认为没有规则告诉任何人不要使用文字数组,IMO 这真的是一个品味问题
  • @AnthonyAlberto:这与我多年来看到的许多风格指南一致。因为这不仅仅是我偶然发现的一些随机样式指南,而是 IDE 本身的建议,我想知道这个断言是否有任何内容我应该更喜欢 %w - 并不是说​​ IDE 说“做 ABC”意味着我应该做ABC...
  • 参考我发布的基准测试结果,我认为使用%w 的好处是它可以产生更清晰的定义,不需要太多维护。从长远来看,维护成本很高。
  • 顺便说一句:两者都是文字数组。
  • 这个问题不应该被关闭。这是一个具体的、可以回答的问题。它不受辩论的影响。 isis not 字面量数组和使用 %w 语法声明的数组之间存在差异。

标签: ruby


【解决方案1】:

瞧!,一个基准:

require 'benchmark'

n = 1_000_000
Benchmark.bm(11) do |b|
  b.report('%w') { n.times { %w[a b c d e f g h i j k l m n o p q r s t u v w x y z] } }
  b.report('explicit') { n.times { ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] } }
  b.report('numerics') { n.times { [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] } }
end

                  user     system      total        real
%w            2.590000   0.000000   2.590000 (  2.591225)
explicit      2.590000   0.000000   2.590000 (  2.584781)
numerics      0.300000   0.000000   0.300000 (  0.309161)

                  user     system      total        real
%w            2.590000   0.000000   2.590000 (  2.591516)
explicit      2.590000   0.000000   2.590000 (  2.584155)
numerics      0.300000   0.000000   0.300000 (  0.308896)

                  user     system      total        real
%w            2.590000   0.000000   2.590000 (  2.592848)
explicit      2.590000   0.000000   2.590000 (  2.585558)
numerics      0.300000   0.000000   0.300000 (  0.308570)

我添加了“numerics”数组测试,因为我怀疑%w 比使用显式字符串更快,因为测试字符串。 %w 不需要这样做,因为它假定一切都是字符串。运行三遍后,就处理字符串而言,它是一次洗涤。数字规则,字符串流口水等等。


之前的基准测试是在我的工作系统上使用 Ruby 1.9.3-p286 运行的。我在家中使用我的旧 MacBook Pro 再次进行了测试,使用 Ruby 1.8.7-p358,因此由于托管硬件的差异以及运行旧 Ruby,以下数字会变慢:

                user     system      total        real
%w           3.070000   0.000000   3.070000 (  3.080983)
explicit     3.100000   0.000000   3.100000 (  3.093083)
numerics     0.950000   0.040000   0.990000 (  0.990535)

                user     system      total        real
%w           3.080000   0.010000   3.090000 (  3.076787)
explicit     3.090000   0.000000   3.090000 (  3.089246)
numerics     0.950000   0.030000   0.980000 (  0.989579)

                user     system      total        real
%w           3.080000   0.000000   3.080000 (  3.073877)
explicit     3.090000   0.000000   3.090000 (  3.091576)
numerics     0.950000   0.030000   0.980000 (  0.989132)

在 1.8.7 上,%w 一直快一点,这可能引起了速度传闻。

【讨论】:

  • +1:很好。在这里至少学到了 3 件事。
  • 两者完全一样。如果甚至任何性能差异,它可能解析期间。 不可能可能有任何运行时性能差异,因为两者是完全相同的东西。由于整个文件在基准测试开始之前被解析,因此整个基准测试毫无意义。您需要使用 evalload 或类似的东西来延迟解析,直到基准测试开始之后。
  • @JörgWMittag 你断言它们是完全相同的东西;但这仅适用于足够智能的编译器。 %w{...} 始终是文字数组,而 [...] 可以是文字数组或表达式数组或混合。编译器可以在解析后分析数组以了解它是一个文字数组,因此在代码生成时完全构造它,但这并不是一个完全微不足道的优化,应该始终假设您在没有文档、测试或代码检查的情况下获得。
  • @dbenhur:这里不需要智能编译器。在 JRuby 和 Rubinius 上,这两段代码都被解析为 完全相同 AST,它们甚至正确地到达编译器之前。在 YARV 上,AST 略有不同,但生成的字节码是相同的:putstring 'a'; putstring 'b'; putstring 'c'; newarray 3;。请注意,YARV 编译器非常不是 SSC,相反:它是一个非常愚蠢的编译器。
  • @JörgWMittag ruby​​ 实现非常简单。我什至不确定 mri 是否进行简单的编译时常量表达式评估。我的观点是,不能假设 %w{} 和 [literals] 会在没有实际调查的情况下编译为相同的代码和数据。您通过发布指向编译器代码的指针来反复断言他们这样做但没有证明这一点,这使得它变得清晰,或者向我们展示了一个示例 AST/字节码输出来证明它们的等价性。在不证明你的断言的情况下贬低通过基准进行调查的尝试只是令人讨厌。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-13
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多