代码之家  ›  专栏  ›  技术社区  ›  James A. Rosen

为什么Ruby没有真正的StringBuffer或Stringio?

  •  52
  • James A. Rosen  · 技术社区  · 17 年前

    我最近读了一本好书 post 关于使用 StringIO 红宝石。但作者没有提到的是 斯特林吉奥 只是一个“I”。没有“O”。你 不能 执行此操作,例如:

    s = StringIO.new
    s << 'foo'
    s << 'bar'
    s.to_s
    # => should be "foo\nbar"
    # => really is ''`
    

    Ruby真的需要一个像Java一样的缓存缓冲区。字符串缓冲区有两个重要用途。首先,他们让您测试Ruby的Stringio所做的一半输出。第二,它们对于从小部分构建长字符串很有用——乔尔一遍又一遍地提醒我们,否则很慢。

    有好的替代品吗?

    Ruby中的字符串确实是可变的,但这并不意味着我们应该始终依赖于该功能。如果 stuff 是大的,性能和内存的要求,例如,真的很差。

    result = stuff.map(&:to_s).join(' ')
    

    在Java中使用“正确”的方法是:

    result = StringBuffer.new("")
    for(String s : stuff) {
      result.append(s);
    }
    

    虽然我的Java有点生疏了。

    5 回复  |  直到 6 年前
        1
  •  114
  •   Stefan    11 年前

    我查看了Ruby文档 StringIO 看起来你想要的是 StringIO#string 不是 StringIO#to_s

    因此,将代码更改为:

    s = StringIO.new
    s << 'foo'
    s << 'bar'
    s.string
    
        2
  •  34
  •   Colin Curtin    16 年前

    与Ruby中的其他IO类型对象一样,当您写入IO时,字符指针会前进。

    >> s = StringIO.new
    => #<StringIO:0x3659d4>
    >> s << 'foo'
    => #<StringIO:0x3659d4>
    >> s << 'bar'
    => #<StringIO:0x3659d4>
    >> s.pos
    => 6
    >> s.rewind
    => 0
    >> s.read
    => "foobar"
    

    给这只猫剥皮的另一种方法。

        3
  •  21
  •   sokkyoku    6 年前

    我做了一些基准测试,最快的方法是使用 String#<< 方法。使用 StringIO 有点慢。

    s = ""; Benchmark.measure{5000000.times{s << "some string"}}
    =>   3.620000   0.100000   3.720000 (  3.970463)
    
    >> s = StringIO.new; Benchmark.measure{5000000.times{s << "some string"}}
    =>   4.730000   0.120000   4.850000 (  5.329215)
    

    使用连接字符串 String#+ 方法是许多数量级中最慢的方法:

    s = ""; Benchmark.measure{10000.times{s = s + "some string"}}
    =>   0.700000   0.560000   1.260000 (  1.420272)
    
    s = ""; Benchmark.measure{10000.times{s << "some string"}}
    =>   0.000000   0.000000   0.000000 (  0.005639)
    

    所以我认为正确的答案是等价于Java的 StringBuffer 只是使用 弦乐器& lt; 红宝石。

        4
  •  11
  •   palmsey    17 年前

    您的示例在Ruby中有效-我刚刚尝试过。

    irb(main):001:0> require 'stringio'
    => true
    irb(main):002:0> s = StringIO.new
    => #<StringIO:0x2ced9a0>
    irb(main):003:0> s << 'foo'
    => #<StringIO:0x2ced9a0>
    irb(main):004:0> s << 'bar'
    => #<StringIO:0x2ced9a0>
    irb(main):005:0> s.string
    => "foobar"
    

    除非我找不到你用来输出对象ID的原因。

        5
  •  3
  •   Mike Stone    17 年前

    好吧,在Ruby中,StringBuffer并不是那么必要,主要是因为Ruby中的字符串是可变的…因此,您可以通过修改现有字符串而不是使用每个concat构造新字符串来构建字符串。

    作为注释,您还可以使用特殊的字符串语法,在这里您可以构建一个引用字符串中其他变量的字符串,这使得字符串的构造非常可读。考虑:

    first = "Mike"
    last = "Stone"
    name = "#{first} #{last}"
    

    这些字符串还可以包含表达式,而不仅仅是变量…例如:

    str = "The count will be: #{count + 1}"
    count = count + 1
    
    推荐文章