Ruby - Ошибка доступа к переменным экземпляра
Я изучаю Ruby, и у меня возникли проблемы при создании программы.
У меня есть класс "LineAnalyzer", который имеет 4 параметра (2 предусмотрено и 2 рассчитано). Оба вычисляемых параметра: @high_wf_count (целое число) и @high_wf_words (массив). Тогда у меня есть этот:
class Solution < LineAnalyzer
attr_reader :analyzers,
:highest_count_across_lines,
:highest_count_words_across_lines
def initialize
@analyzers = []
end
def analyze_file
File.foreach('test.txt') do |line|
@analyzers << LineAnalyzer.new(line.chomp,@analyzers.length+1)
end
end
def calculate_line_with_highest_frequency
@highest_count_words_across_lines = []
@highest_count_across_lines = @analyzers.max_by do
|a| a.instance_variable_get(:@highest_wf_count)
end .instance_variable_get(:@highest_wf_count)
@highest_count_words_across_lines << @analyzers.each do
|a| a.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
end .instance_variable_get(:@highest_wf_words)
end
end
Проблема в том, что я не могу добавить массив @highest_wf_count
в @highest_count_words_across_lines
так, как я сделал (возвращается nil
). Но я ранее взял целое число @highest_wf_count
точно так же отлично.
Может кто-нибудь сказать мне, где проблема?
Заранее спасибо!
3 ответа
Кажется, что ваша проблема в следующем фрагменте кода:
@highest_count_words_across_lines << @analyzers.each do
|a| a.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
end .instance_variable_get(:@highest_wf_words)
Желательно отформатировать как:
@highest_count_words_across_lines << @analyzers.each do |analyzer|
analyzer.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
end.instance_variable_get(:@highest_wf_words)
Проблема в том, что вы звоните .instance_variable_get(:@highest_wf_words)
на результат :each
метод.
Несколько строк выше, вы делаете что-то подобное, где вы звоните .instance_variable_get(:@highest_wf_count)
на результат :max_by
метод, и он работает.
Разница между :max_by
а также :each
в том, что :max_by
возвращает один анализатор, тогда как :each
возвращает массив @analyzers
по которому это повторяется.
Когда вы звоните :instance_variable_get(:@highest_wf_words)
в этом массиве он возвращает nil
потому что массив не будет иметь переменную экземпляра с именем :@highest_wf_words
Вот где ваша проблема существует.
Примечание:
Обычно не рекомендуется использовать :instance_variable_get
, Я бы порекомендовал добавить в свой класс анализатора attr_reader :highest_wf_words, :highest_wf_count
Тогда вместо звонка analyzer.instance_variable_get(:@highest_wf_words)
Вы можете просто позвонить analyzer.highest_wf_words
Здесь много чего происходит, и большая часть кода получается из-за несоответствия при написании Ruby. С помощью instance_variable_get
должен быть абсолютным последним средством. Считается очень грубым просто достать объект и вытащить переменную. Это создает уродливые и нежелательные взаимозависимости. Если этот другой объект хочет дать вам это значение, у него будет метод для доступа к нему.
То, как я вижу, то, что вы пытаетесь сделать, сводится к следующему:
def highest_frequency
@analyzers.map do |a|
a.highest_wf_count
end.sort.last
end
Позволять Analyzer
воплощать в жизнь highest_wf_count
в качестве метода, даже если это просто attr_reader
, Это дает вам гибкость в изменении того, как и когда вычисляется это значение. Может быть, вам не нужно делать это, когда объект инициализирован. Может быть, это сделано в другой теме, или это оценивается лениво.
По возможности старайтесь структурировать свой код как серию простых преобразований. Старайтесь не создавать запутанных, ветвящихся, безобразных сравнений. Опирайтесь на Enumerable всякий раз, когда это возможно, обычно у него есть метод, который делает именно то, что вы хотите, или два, которые в совокупности делают работу отлично.
Это намного сложнее, чем нужно (или должно быть).
Почему Solution
подкласс LineAnalyzer
? И почему вы используете instance_variable_get
? Вы должны определить методы получения, используя attr_reader
в классе LineAnalyzer, чтобы вы могли вызывать методы вместо instance_variable_get
, который является подходом грубой силы, который должен использоваться только в качестве крайней меры.
Я думаю, вы должны это исправить, прежде чем продолжить.
Когда у вас есть методы экземпляра, созданные с помощью attr_reader, вычисление max становится очень простым:
highest_count_across_lines = @analyzers.map(&:highest_wf_count).max
Я думаю, что ваша ошибка, вероятно, вызвана этими строками:
@highest_count_words_across_lines << @analyzers.each do
|a| a.instance_variable_get(:@highest_wf_count) == @highest_count_across_lines
end .instance_variable_get(:@highest_wf_words)
Я предлагаю упростить этот код, и ошибка, вероятно, представится вам. Вы действительно хотели добавить значение, возвращаемое each
@highest_count_words_across_lines? Это будет массив анализаторов. Класс Array, конечно, не имеет переменной с именем :@highest_wf_words
,
Опять же, я думаю, вам действительно нужно упростить этот код.