代码之家  ›  专栏  ›  技术社区  ›  Stewart Johnson

为什么我用inject重构的ruby不能工作?

  •  3
  • Stewart Johnson  · 技术社区  · 14 年前

    我试着做一些重构来将一个each块转换成一个inject,但是没有成功,我也不明白为什么。

    class String
      # Build the word profile for the given word. The word profile is an array of
      # 26 integers -- each integer is a count of the number of times each letter
      # appears in the word. 
      #
      def profile
        profile = Array.new(26) { 0 }
        self.downcase.split(//).each do |letter|
          # only process letters a-z
          profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord
        end
        profile
      end
    end
    

    我的重构失败了:

    class String
      # Build the word profile for the given word. The word profile is an array of
      # 26 integers -- each integer is a count of the number of times each letter
      # appears in the word. 
      #
      def profile
        self.downcase.split(//).inject(Array.new(26) {0}) do |profile, letter|
          # only process letters a-z
          profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord 
        end
      end
    end
    

    `block in profile': undefined method `[]=' for 1:Fixnum (NoMethodError)
    

    如果我理解正确的话,它与重构版本中profile对象上的array引用操作符不同,这意味着传递给inject的初始化器不起作用。这种理解正确吗?如果是,为什么不呢?

    谢谢!

    1 回复  |  直到 14 年前
        1
  •  3
  •   Chuck    14 年前

    这个 []= 方法返回赋值,因此 profile

    self.downcase.split(//).inject(Array.new(26) {0}) do |profile, letter|
      # only process letters a-z
      profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord 
      profile
    end
    

    self.downcase.split(//).inject(Array.new(26) {0}) do |profile, letter|
      # only process letters a-z
      profile.tap { profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord }
    end