O que ||= faz

Prévia grátis 3 min de leitura

Um operador, dois caracteres trabalhando

x = nil
x ||= 5
x
# 5

||= parece uma sintaxe própria, mas junta duas coisas de cursos anteriores: || (OU com curto-circuito) e = (atribuição). x ||= 5 funciona assim:

x || (x = 5)

O Ruby avalia x primeiro. Se x é truthy, esse é o valor da expressão inteira, e (x = 5) nunca roda. Se x é falsy (nil ou false), o Ruby cai para (x = 5), roda a atribuição, e ela vira o valor. Então ||= não quer dizer "atribua um padrão". Quer dizer "atribua, mas só se o lado esquerdo ainda não deu algo utilizável".

Funciona numa variável nova

defined?(x)
# nil — x ainda não existe como variável
x ||= 5
x
# 5
defined?(x)
# "local-variable" — agora existe

Vale checar, porque parece que não deveria funcionar. Como x || (x = 5) lê x à esquerda do || antes de x ter sido atribuído? O parser do Ruby resolve isso quando lê o código, e não quando o roda. Ver x = numa instrução faz x ser uma variável local na instrução inteira, inclusive na parte antes do =. Ler uma variável local intocada assim dá nil, que é falsy, então o lado direito roda, x recebe 5, e a variável passa a existir. Não há erro nem caso especial no código que escreve x ||= 5; é como a expansão e as regras de variáveis do Ruby se encaixam.

O mesmo vale para variáveis de instância

class Foo
  def bar
    @bar ||= 10
  end
end

f = Foo.new
f.instance_variable_defined?(:@bar)
# false
f.bar
# 10
f.instance_variable_defined?(:@bar)
# true

Antes de bar ser chamado, @bar não existe em f, nem como nil, então instance_variable_defined? devolve false. Chamar f.bar roda @bar ||= 10. Ele lê @bar, que dá nil para uma variável de instância indefinida, como para uma local indefinida, sem erro. Acha falsy e atribui 10. Depois dessa chamada, @bar existe em f. É sobre esse comportamento em variáveis de instância que o resto do curso se apoia.

Pontos-chave

  • x ||= value funciona como x || (x = value): a atribuição só roda quando x é falsy (nil ou false).
  • ||= funciona numa variável nunca atribuída: o parser a trata como local assim que vê o =, e uma local intocada é lida como nil.
  • O mesmo vale para variáveis de instância: uma @ivar indefinida é lida como nil, então @ivar ||= value a atribui na primeira vez que ela é falsy.
  • ||= quer dizer "defina isto, mas só se ainda não for truthy", o que é mais estreito que "defina um padrão".
Aula 1 de 7 · grátis

Continue com a aula 2

||= para valores padrão

Usos de ||= em partials e helpers desta app que dão valores padrão sem guardar nada num objeto.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...