O que ||= faz
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 ||= valuefunciona comox || (x = value): a atribuição só roda quandoxé falsy (niloufalse).||=funciona numa variável nunca atribuída: o parser a trata como local assim que vê o=, e uma local intocada é lida comonil.- O mesmo vale para variáveis de instância: uma
@ivarindefinida é lida comonil, então@ivar ||= valuea 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".
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.