Recipe 1.1. Building a String from Parts

Recipe 1.1. Building a String from Parts

Problem
你可以考虑使用一个string来描述一个数据结构

Solution
下面有2个有效的办法。一个简单的方法就是先创建一个空的string,然后用<< operator追加字符串进去(append substring):
    hash = { "key1" => "val1", "key2" => "val2" }
    string = ""
    hash.each { |k,v| string << "#{k} is #{v}/n" }
    puts string
    # key1 is val1
    # key2 is val2

下面这个方法稍微效率高一点,但是可读性略差:
    string = ""
    hash.each { |k,v| string << k << " is " << v << "/n" }

如果数据结构是一个数组,或者容易转成数组的数据结构,通常用Array#join更有效率:
    puts hash.keys.join("/n") + "/n"
    # key1
    # key2
注释:
  join          arr.join( aSepString=$, ) -> aString
  转化数组中的每个element,成为一个字符串,中间用参数aSepString分隔.例:
[ "a", "b", "c" ].join     #"abc"
[ "a", "b", "c" ].join("-")     #"a-b-c"


Discussion
在Python和Java里,用先创建一个字符串然后追加的方式创建字符串,效率是非常差的.在这些语言中,字符串是不可以改变的,添加一个字符
串到另外一个字符串,会导致重新创建一个新的字符串。多次这样的操作会导致产生一个巨大的中间的或者说临时的string,这样导致浪费了
大量的时间和内存。

In those languages, the most efficient way to build a string is always to put the substrings into an array or another
mutable data structure, one that expands dynamically rather than by implicitly creating entirely new objects. Once you're
done processing the substrings, you get a single string with the equivalent of Ruby's Array#join. In Java, this is the
purpose of the StringBuffer class.

在Ruby中,string相当于可变的数组,他们可以很有效率的扩张,不需要太多的时间和空间.对于这个问题,在Ruby中最快的解决方法通常是:
在当前的字符串数组后面直接增加字符串,改变字符串数组本身(forgo a holding array and tack the substrings directly onto a
base string).大多数情况下使用Array#join是效率很高的,但是可能感觉不太自然(pretty close),而<<看上去比较容易理解.

如果当前效率优先的话,当追加一个字符串到一个已经存在的字符串里面的时候,不要去创建一个新的字符串.像str << 'a' + 'b'或者
str << "#{var1} #{var2}",都会创建一个新的字符串追加到已经存在的字符串.这种情况我们需要尽量避免.请使用这样的方式:
str << var1 <<''<< var2

另外,你最好不要修改不是属于你的字符串.基于安全的考虑,你创建了一个字符串,当你定义了一个方法用一个字符串作为参数,你最好不
要修改这个字符串,除非你确定这个函数就是需要这么做(或者这个函数有一个感叹号,表示调用者知道这个函数会修改它).

Another caveat: Array#join和重复追加的方式还是不完全一样的.Array#join使用一个separator string来分隔数组中的每个元素,追加
最后一个元素的时候它不会再插入一个separator string.下面的例子描述了其中的差别:

    data = ['1', '2', '3']
    s = ''
    data.each { |x| s << x << ' and a '}
    s                                             # => "1 and a 2 and a 3 and a "
    data.join(' and a ')                          # => "1 and a 2 and a 3"

为了模拟Array#join的反复追加,你可以用Enumerable#each_with_index,并且在最后一个元素的时候忽略separator string.
    s = ""
    data.each_with_index { |x, i| s << x; s << "|" if i < data.length-1 }
    s                                             # => "1|2|3"
 

你可能感兴趣的:(Ruby,CookBook翻译)