Ruby的变量是否等于变量等于方法?

时间:2018-08-08 23:21:42

标签: ruby if-statement

我正在阅读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我主要是想知道如何阅读此功能/是否有更好的方法来重写此代码以使其更具可读性?

1 个答案:

答案 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]),而不是两次计算identifierconstantnumber第一次计算它们。 (这些赋值是在应用ifelsif之前进行评估的。)通常在这种计算成本高昂或执行不止一次时具有不希望的副作用时,通常这样做。以这种方式使用临时变量也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也为真。