Ruby - 访问实例变量

时间:2016-05-21 19:08:17

标签: arrays ruby each instance-variables

我正在学习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 个答案:

答案 0 :(得分:2)

看来你的问题出现在这段代码中:

@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

答案 1 :(得分:2)

这里有很多内容,大多数代码都是在编写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,通常会有一种方法可以完全按照你想要的方式,或者两种方法完美地完成工作。

答案 2 :(得分:1)

这比它需要(或应该是)更复杂。

为什么Solution子类LineAnalyzer?你为什么要使用instance_variable_get?您应该在LineAnalyzer类上使用attr_reader定义getter方法,这样您就可以调用方法而不是使用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的变量。

同样,我认为你真的需要简化这段代码。