在自己内部调用方法是不好的做法吗?

Che*_*ter 2 ruby coding-style

我正在创建一个简短的程序来查找给定数字集的平均值.这是一个程序,其基本结构首先在TI-83上用goto语句编写,所以我对这种事情的正确实践有点不确定.这是有问题的代码:

$sum     = 0
$counter = 0

def average
  puts "Input another number, or \"end\" to end."
  input = gets.chomp
  if input == "end"
    puts $counter
    puts ($sum / $counter).to_f
  else
    $sum += input.to_f
    $counter += 1
    puts $counter
    average #Here the method is called again, repeating the cycle.
  end
end
Run Code Online (Sandbox Code Playgroud)

我不确定如何做到这一点,因为像这样构建的代码点是它可以处理不确定数量的输入,因此它重复性质.

Ama*_*dan 5

在具有所谓的"尾部调用优化"的语言中,这种结构是循环的主要方式.然而,Ruby却没有; 递归(重新输入已经输入的函数)是常用的,但不能作为简单循环的一般替代,就像在这种情况下一样.

在这里,正如pvg所说,一个while(或等价的until)循环更好:

sum = 0
counter = 0
puts "Input a number, or \"end\" to end."
input = gets.chomp
until input == "end"
  sum += input.to_f
  counter += 1
  puts "Input another number, or \"end\" to end."
  input = gets.chomp
end
puts sum / counter
Run Code Online (Sandbox Code Playgroud)

或者是一个无限循环break:

sum = 0
counter = 0
loop do
  puts "Input a number, or \"end\" to end."
  input = gets.chomp
  break if input == "end"
  sum += input.to_f
  counter += 1
end
puts sum / counter
Run Code Online (Sandbox Code Playgroud)

但是你也可以使用更多的Ruby方式:

puts 'Input numbers, or "end" to end.'
array = STDIN.each_line.lazy
  .map(&:chomp)
  .take_while { |line| line != "end" }
  .map(&:to_f)
  .to_a
puts array.inject(&:+) / array.size
Run Code Online (Sandbox Code Playgroud)

或者更丑陋但内存效率更高:

puts 'Input numbers, or "end" to end.'
sum, count = *STDIN.each_line.lazy
  .map(&:chomp)
  .take_while { |line| line != "end" }
  .inject([0, 0]) { |memo, x|
    [memo[0] + x.to_f, memo[1] + 1]
  }
puts sum / count
Run Code Online (Sandbox Code Playgroud)