Неявные возвращаемые значения в Ruby

Я немного новичок в Ruby, и хотя я нахожу его очень интуитивным языком, мне трудно понять, как ведут себя неявные возвращаемые значения.

Я работаю над небольшой программой для создания журналов Tomcat и создания CSV-файлов с разделителями из соответствующих данных. Вот упрощенный пример, который я использую для генерации строк из записи журнала.

class LineMatcher
  class << self
    def match(line, regex)
      output = ""
      line.scan(regex).each do |matched|
        output << matched.join("|") << "\n"
      end
      return output
    end        
  end
end


puts LineMatcher.match("00:00:13,207 06/18 INFO  stateLogger - TerminationRequest[[email protected][accountNumber=0951714636005,srNumber=20]",
                       /^(\d{2}:\d{2}:\d{2},\d{3}).*?(\d{2}\/\d{2}).*?\[accountNumber=(\d*?),srNumber=(\d*?)\]/)

Когда я запускаю этот код, я получаю следующее, что и ожидается при явном возвращении значения вывода.

00:00:13,207|06/18|0951714636005|20

Однако, если я изменю LineMatcher на следующее и явно не верну вывод:

    class LineMatcher
      class << self
        def match(line, regex)
          output = ""
          line.scan(regex).each do |matched|
            output << matched.join("|") << "\n"
          end
        end        
      end
    end

Тогда я получаю следующий результат:

00:00:13,207
06/18
0951714636005
20

Очевидно, что это не желаемый результат. Такое чувство, что я должен быть в состоянии избавиться от выходной переменной, но неясно, откуда возвращается значение. Также приветствуются любые другие предложения / улучшения для удобства чтения.

 csamuel30 июн. 2009 г., 18:05
Исправленное форматирование

Ответы на вопрос(2)

возвращаемое последним оператором. Вы также можете выбрать явный возврат.

В вашем примере первый фрагмент возвращает строкуoutput. Второй фрагмент, однако, возвращает значение, возвращаемоеeach метод (который теперь является последним stmt), который оказывается массивом совпадений.

irb(main):014:0> "StackOverflow Meta".scan(/[aeiou]\w/).each do |match|
irb(main):015:1* s << match
irb(main):016:1> end
=> ["ac", "er", "ow", "et"]

Обновление: Тем не менее, это не объясняет ваш вывод в одной строке. Я думаю, что это ошибка форматирования, она должна печатать каждое совпадение в отдельной строке, потому что вот такputs печатает массив. Небольшой код может объяснить это лучше, чем я ..

irb(main):003:0> one_to_three = (1..3).to_a
=> [1, 2, 3]
irb(main):004:0> puts one_to_three
1
2
3
=> nil

Лично я считаю ваш метод с явным возвратом более читабельным (в данном случае)

 csamuel30 июн. 2009 г., 18:06
Извините, да, у меня была ошибка форматирования. Исправлено в вопросе.
Решение Вопроса

ния. Вам нужно знать реализацию и поведение наиболее часто используемого метода, чтобы точно знать, как будет действовать ваша программа.

#each возвращает коллекцию, которую вы повторяли. Тем не менее, следующий код вернет значение line.scan (regexp).

line.scan(regex).each do |matched|
  output << matched.join("|") << "\n"
end

Если вы хотите вернуть результат выполнения, вы можете использоватьmap, который работает какeach но возвращает измененную коллекцию.

class LineMatcher
  class << self
    def match(line, regex)
      line.scan(regex).map do |matched|
        matched.join("|")
      end.join("\n") # remember the final join
    end        
  end
end

Есть несколько полезных методов, которые вы можете использовать в зависимости от вашего конкретного случая. В этом вы можете использоватьinject если только число результатов не возвращеноscan высокий (работа с массивами, а затем их объединение более эффективна, чем работа с одной строкой).

class LineMatcher
  class << self
    def match(line, regex)
      line.scan(regex).inject("") do |output, matched|
        output << matched.join("|") << "\n"
      end
    end        
  end
end
 csamuel30 июн. 2009 г., 17:57
Спасибо за отзыв ... Я думаю, что моя путаница возникла из-за того, что было трудно сказать, что на самом деле интерпретируется как последнее утверждение.

Ваш ответ на вопрос