2016-04-26 92 views
1

我在Ruby中编写了一个编译器,并且我有许多实例方法将修改实例变量的类。例如,我的词法分析器(即在代码中发现的标记部分),工作原理是这样的:应该在Ruby中修改实例变量吗?

class Lexer 
    attr_accessor :tokens 

    def initialize(input) 
    @input = input 
    @tokens = nil 
    end 

    def lex! 
    # lex through the input... 
    # @tokens << { lexeme: 'if', kind: :if_statement } 

    @tokens 
    end 
end 

lexer = Lexer.new('if this then that') 
lexer.lex! # => [ { lexeme: 'if', kind: :if_statement }, ... ] 
lexer.tokens # => [ { lexeme: 'if', kind: :if_statement }, ... ] 

这是一个有效的做法呢?或者,我是否应该使用方法(如#lex)接受输入并返回结果,而不修改实例变量?

class Lexer 
    def initialize 
    end 

    def lex(input) 
    # lex through the input... 
    # tokens << { lexeme: 'if', kind: :if_statement } 

    tokens 
    end 
end 

lexer = Lexer.new 
lexer.lex('if this then that') # => [ { lexeme: 'if', kind: :if_statement }, ... ] 

回答

1

根据您的设计目标以及词法分析器的使用方式,这两种方法都是有效的。

你实际上需要一个包含令牌的实例变量吗?例如,词法分析器是否需要将它们用于其他任何事情?如果不是,我会倾向于不使用实例变量,并且你不需要推理(例如,“这个实例变量是否会被其他系统交互所改变”)。

+0

不,它不会用'@ tokens'做任何事情。我认为这几乎可以回答我的问题,谢谢! –

+0

@EthanTurkeltaub \t这是一种功能性与非功能性的方法,真的。 –

1

在一个实例的方法中改变一个实例变量是完全有效的(这就是为什么它们存在于第一位)。但是,某些数据片段是否应保存在实例变量中,取决于您的实例将如何使用。

你能想到的实例变量为您的实例的状态的,和你的情况为你的实例变量状态管理的。例如,如果您有Counter类,例如incrementdecrement方法,则计数器的当前值显然是状态的一部分,并且这些方法会改变它。

一个好的经验法则是:是否会来回传递数据?如果你是,那么它可能应该是一个实例变量。如果你不是,那么它不是你的实例状态的一部分,应该保持在它之外。你的情况:

lexer = Lexer.new 
tokens = lexer.lex('my statement') 
lexer.do_something_else tokens # if you do that, then lexer should be aware of the tokens and keep it in an instance variable, if not: why bother ? 

作为结论,这一切都取决于Lexer是否是功能性的实用工具类,或者如果它的实例必须是有状态的。