为什么在Ruby中有这么多不同的方法来做同样的事情?
我正在学习Ruby。 我的背景是C ++ / Java / C#。 总的来说,我喜欢这种语言,但我有点困惑为什么有很多不同的方法可以完成同样的事情,每种方法都有自己稍微不同的语义。
例如,创建字符串。 我可以使用”,“”,q%,Q%或只是%来创建字符串。 某些forms支持插值。 其他forms允许我指定字符串分隔符。
为什么有五种方法来创建字符串文字? 为什么我会使用非插值字符串? %语法比引用文字有什么优势?
我知道Ruby中的redundency一定有价值,但是我未经训练的眼睛并没有清楚地看到它。 请赐教。
为什么我会使用非插值字符串?
当然,当你不想要插值时。 例如,也许你正在输出一些关于字符串插值的文档:
'Use #{x} to interpolate the value of x.' => "Use #{x} to interpolate the value of x."
%语法比引用文字有什么优势?
它允许您更自然地编写字符串,不带引号,或者当您不想逃避很多事情时,类似于C#的字符串文字前缀@
。
%{The % syntax make strings look more "natural".} => "The % syntax makes strings look more \"natural\"." %{} => " "
还有许多其他%注释:
%w{apple banana #{1}cucumber} # [w]hitespace-separated array, no interpolation => ["apple", "banana", "\#{1}cucumber"] %W{apple banana #{1}cucumber} # [W]hitespace-separated array with interpolation => ["apple", "banana", "1cucumber"] # [r]egular expression (finds all unary primes) %r{^1?$|^(11+?)\1+$} => /^1?$|^(11+?)\1+$/ (1..30).to_a.select{ |i| ("1" * i) !~ %r{^1?$|^(11+?)\1+$} } => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] %x{ruby --version} # [s]hell command => "ruby 1.9.1p129 (2009-05-12 revision 23412) [x86_64-linux]\n"
还有%s
(用于符号)和其他一些。
为什么有五种方法来创建字符串文字?
这不是特别不寻常。 例如,考虑C#,它有几种不同的方式来生成字符串: new String()
; ""
; @""
; StringBuilder.ToString()
等等。
我不是Ruby专家,但你有没有听说过“语法糖”这个词? 基本上一些编程语言提供不同的语法来完成相同的任务。 由于他之前的编程/语法经验,有些人可以找到比其他人更容易的方法。
在大多数情况下,您最终会使用普通的字符串分隔符。 单引号和双引号之间的主要区别在于双引号允许您插入变量。
puts 'this is a string' # => this is a string puts "this is a string" # => this is a string v = "string" puts 'this is a #{v}' # => this is a #{v} puts "this is a #{v}" # => this is a string
%q
和%Q
在您不能使用引号时很有用,因为它们是内部字符串的一部分。 例如,您最终可能会写作
html = %Q{this is a image tag}
在这种情况下,除非要转义内部属性分隔符,否则不能将双引号用作分隔符。 此外,您不能使用单引号,因为img_path
变量不会被插值。
很多ruby的语法都是从perl派生的,比如用q
来引用一些单词到字符串中。 这可能是种类繁多的主要原因。
另一个原因是非插值字符串的性能提升很小。 使用”vs“”意味着Ruby根本不必考虑字符串中的内容。 所以你会看到人们使用数字键或符号的单引号,因为它们更快。 对于它的价值,我将包括一些基准。
require 'benchmark' Benchmark.bmbm(10) do |x| x.report("single-quote") do for z in 0..1000000 zf = 'hello' end end x.report("double-quote") do for z in 0..1000000 zf = "hello" end end x.report("symbol") do for z in 0..1000000 zf = :hello end end end
收益率:
Rehearsal ------------------------------------------------ single-quote 0.610000 0.000000 0.610000 ( 0.620387) double-quote 0.630000 0.000000 0.630000 ( 0.627018) symbol 0.270000 0.000000 0.270000 ( 0.309873) --------------------------------------- total: 1.580000sec
如果你的字符串包含很多特殊字符(比如反斜杠, #{}
等),你会使用非插值字符串,并且你不想逃避所有字符串。
如果你的字符串包含很多你必须要逃脱的引号,你会使用不同的分隔符。
如果你的字符串有很多行会使正常的字符串语法看起来不实用,你就会使用heredocs。
Ruby从许多语言中借用了构造和想法。 两个最明显的影响是Smalltalk和Perl。
根据您对Smalltalk或Perl的舒适度,您可以选择不同的结构来做同样的事情。
按照约翰的回答:在快速黑客攻击中,我经常会在我的ruby脚本中使用grep语法运行perl或sed单行程序。 能够使用%[ ]
类型语法意味着我可以简单地从终端复制粘贴我的正则表达式
最初的问题是为什么在Ruby中有这么多不同的做事方式。
有时候不同的东西是明智的:引用是一个很好的例子,不同的行为需要不同的语法 – 非/插值,交替引用字符等 – 而历史意识导致像%x()vs`这样的同义词,就像在Perl中一样。
同义词问题 – [] .size []。length [] .count – 感觉就像是试图在一个语言过于随机的世界中帮助IDE无法提供帮助:猴子修补和严格的奇怪组合但动态类型编码使运行时错误成为编码中不可避免且令人沮丧的部分,因此人们试图通过提供同义词来减少问题。 不幸的是,他们最终混淆了习惯于采用不同方法做不同事情的程序员。
例如,“如此相似但不完全”的问题……
$ ruby -le 'e=[]; e << (*[:A, :B])' -e:1: syntax error, unexpected ')', expecting :: or '[' or '.' $ ruby -le 'e=[]; e << *[:A, :B]' -e:1: syntax error, unexpected * $ ruby -le 'e=[]; e.push(*[:A, :B])' $
......真的只能被视为一个缺陷。 每种语言都有它们,但它们通常比这更神秘。
除非你只是在Rubocop编码标准中重新抛出exception'废话,否则就会出现明显的任意'使用失败而不是提升。
Ruby中有一些不错的东西,但实际上 - 我宁愿在更好的基础上编写代码。