Идиоматический рубин для временных переменных в методе - PullRequest
3 голосов
/ 20 мая 2010

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

i = positions.first
while nucleotide_at_position(i-1) == nucleotide_at_position(i)
  raise "Assumption violated" if i == 1
  i -= 1
end
first_nucleotide_position = i
j = positions.last
while nucleotide_at_position(j+1) == nucleotide_at_position(j)
  raise "Assumption violated" if j == sequence.length
  j += 1
end
last_nucleotide_position = j

Справочная информация: Я бы хотел избавиться от i и j, когда они больше не нужны, чтобы они не использовались никаким другим кодом в методе. Дает моему коду меньше возможности ошибиться. Я не знаю названия концепции - это «инкапсуляция»? Самые близкие понятия, которые я могу придумать (предупреждение: ссылки на ТВ-Тропы - не посещайте во время работы) Чеховская пушка или YouHaveOutlivedYourUsefulness .

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

Ответы [ 5 ]

4 голосов
/ 20 мая 2010

Что заставляет вас думать, что разбиение кода на несколько методов ухудшит читабельность? По моему опыту, разбиение даже небольших или средних по размеру фрагментов кода на несколько методов может значительно улучшить читаемость.

2 голосов
/ 20 мая 2010

Ruby (как JS) не создает новую область видимости для каждого блока по умолчанию (как это делают C ++ и т. Д.). Однако в Ruby 1.9 вы можете попробовать:

last_nucleotide_position = nil
proc { |;i, j|
  i = positions.first
  while nucleotide_at_position(i-1) == nucleotide_at_position(i)
    raise "Assumption violated" if i == 1
    i -= 1
  end
  first_nucleotide_position = i
  j = positions.last
  while nucleotide_at_position(j+1) == nucleotide_at_position(j)
    raise "Assumption violated" if j == sequence.length
    j += 1
  end
  last_nucleotide_position = j
}.call()

См. Как сделать локальные переменные блока по умолчанию в ruby ​​1.9? . Любые переменные, которые вы хотите использовать за пределами блока, должны быть определены заранее (например, last_nucleotide_position).

FM прав, что отдельный метод может быть более читабельным.

2 голосов
/ 20 мая 2010

Я думаю, что термин, который вы ищете, является переменной областью действия - другими словами, вы ищете способы ограничить область действия i и j. Но вам не нужно беспокоиться об этом. Проблема под рукой требует создания отдельных методов - независимо от области видимости.

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

def calc_first_nucleotide_position(po)
  i = po.first
  while nucleotide_at_position(i-1) == nucleotide_at_position(i)
    raise "Assumption violated" if i == 1
    i -= 1
  end
  i
end

# etc...

first_nucleotide_position = calc_first_nucleotide_position(positions)
last_nucleotide_position  = calc_last_nucleotide_position(positions)

# etc...
1 голос
/ 13 ноября 2012

Если все, что вам нужно, это не допустить попадания новых переменных в остальную часть вашей программы, вы можете заключить код в блок, используя 1.times. Любые новые переменные, которые вы создаете внутри блока, будут уничтожены при закрытии блока. Просто помните, что любые изменения, внесенные в ранее существующие переменные, останутся после закрытия блока.

y = 20
1.times do
  # put your code in here
  i = 1
  puts x = y # => 20, because y is available from outside the block
  y = 'new value' # We can change the value of y but our changes will 
    # propagate to outside the block since y was defined before we opened
    # the block.
end

defined? i # => nil, i is lost when you close the block
defined? x # => nil, x is also local to the block
puts y # => 'new value'
1 голос
/ 20 мая 2010

Вы ищете Ruby-эквивалент специального оператора Lisp let. Ruby не поддерживает его из коробки, но вы можете взломать его очень легко, и в результате синтаксис выглядит так:

x = 10
scope { |x|
    x = 30
}
puts x #=> 10

см .: http://banisterfiend.wordpress.com/2010/01/07/controlling-object-scope-in-ruby-1-9/

...