我正在用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 }, ... ]
答案 0 :(得分:1)
根据您的设计目标和词法分析器的使用方式,两者都有效。
你真的需要包含令牌的实例变量吗?例如,词法分析者是否需要将它们用于其他任何事情?
如果没有,我倾向于不使用实例变量,并且你没有理由(例如,“这个实例变量会被其他系统交互改变”)。
答案 1 :(得分:1)
在你的一个实例的方法中改变一个实例变量是有效的(这就是它们首先存在的原因)。但是,某些数据是否应保存在实例变量中,取决于您的实例的使用方式。
您可以将实例变量视为实例的状态,将实例视为实例变量的状态管理器。如果你有一个Counter
类,例如increment
和decrement
方法,你的计数器的当前值显然是状态的一部分,这些方法会改变它。
一个好的经验法则是:来回传递数据?如果你是,那么它可能应该是一个实例变量。如果你不是,那么它并不是你实例状态的一部分,应该保持在它之外。在你的情况下:
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
是否是一个功能实用程序类,或者它的实例是否需要是有状态的。