我正在阅读createyourlang这本书,并看到了一个类似于以下内容的代码段:
tokenizer = if identifier = chunk[IDENTIFIER, 1]
IdentifierTokenizer.new(identifier, tokenizer).tokenize
elsif constant = chunk[CONSTANT, 1]
ConstantTokenizer.new(constant, tokenizer).tokenize
elsif number = chunk[NUMBER, 1]
...
我发现在同一行上具有两个等号会造成混淆。拥有A = if B = C
是什么意思?
如果您想知道什么是块,请假设块是字符串"hello"
,并且chunk[IDENTIFIER,1]
等于"hello"
,而其他chunk[OTHER_CONST,1]
等于{{1 }}。该功能有效。您可以找到源代码仓库here。我主要是想知道如何阅读此功能/是否有更好的方法来重写此代码以使其更具可读性?
答案 0 :(得分:6)
是的,这可能会造成混淆,部分是因为人们对看到if identifier = chunk[IDENTIFIER, 1]
的第一反应可能是它可能是一个错误,即作者的意思是if identifier == chunk[IDENTIFIER, 1]
。
问题中给出的代码块可能等效于:
tokenizer =
if chunk[IDENTIFIER, 1]
IdentifierTokenizer.new(chunk[IDENTIFIER, 1], tokenizer).tokenize
elsif chunk[CONSTANT, 1]
ConstantTokenizer.new(chunk[CONSTANT, 1], tokenizer).tokenize
elsif chunk[NUMBER, 1]
NumberTokenizer.new(chunk[NUMBER, 1], tokenizer).tokenize
..
将这些值分配给变量(chunk[IDENTIFIER, 1]
,chunk[CONSTANT, 1]
,chunk[NUMBER, 1]
),而不是两次计算identifier
,constant
和number
第一次计算它们。 (这些赋值是在应用if
和elsif
之前进行评估的。)通常在这种计算成本高昂或执行不止一次时具有不希望的副作用时,通常这样做。以这种方式使用临时变量也DRYs代码,但是实现相同目标的其他方法可能更可取。我个人避免这样的内联变量分配,部分原因是因为我认为它们很丑。
以下是一个更清晰的替代方法,它可以使代码更加干燥。
tokenizer =
tokenit(IDENTIFIER, IdentifierTokenize, tokenizer) ||
tokenit(CONSTANT, ConstantTokenize, tokenizer) ||
tokenit(NUMBER, NumberTokenize, tokenizer) ||
...
def tokenit(type, class, tokenizer)
ch = chunk[type, 1]
if ch
class.public_send(:new, ch, tokenizer).tokenize
else
false
end
end
这当然是假设ch
为真class.public_send(:new, ch, tokenizer).tokenize
也为真。