Sempre que troco valores em uma matriz, certifico-me de que armazenei um dos valores em uma variável de referência. Mas descobri que Ruby pode retornar dois valores, bem como trocar dois valores automaticamente. Por exemplo,
array = [1, 3, 5 , 6 ,7]
array[0], array[1] = array[1] , array[0] #=> [3, 1]
Eu queria saber como Ruby faz isso.
Respostas:
Ao contrário de outras linguagens, o valor de retorno de qualquer chamada de método em Ruby é sempre um objeto. Isso é possível porque, como tudo em Ruby,
nil
ele mesmo é um objeto.Existem três padrões básicos que você verá. Não retornando nenhum valor particular:
Retornando um valor singular:
Isso está de acordo com o que você esperaria de outras linguagens de programação.
As coisas ficam um pouco diferentes ao lidar com vários valores de retorno. Eles precisam ser especificados explicitamente:
Ao fazer uma chamada que retorna vários valores, você pode dividi-los em variáveis independentes:
Essa estratégia também funciona para os tipos de substituição de que você está falando:
fonte
[1, 2]
e isso funcionará da mesma forma que os exemplos acima.1,2
por si só é inválido, mas qualquer umreturn 1,2
ou[1,2]
funciona.Não, Ruby na verdade não suporta o retorno de dois objetos. (BTW: você retorna objetos, não variáveis. Mais precisamente, você retorna ponteiros para objetos.)
No entanto, ele oferece suporte à atribuição paralela. Se você tiver mais de um objeto no lado direito de uma atribuição, os objetos serão coletados em
Array
:Se você tiver mais de um "destino" (variável ou método setter) no lado esquerdo de uma atribuição, as variáveis serão vinculadas aos elementos de um
Array
no lado direito:Se o lado direito não for um
Array
, ele será convertido em um usando oto_ary
métodoE se colocarmos os dois juntos, obtemos que
Relacionado a isso está o operador splat no lado esquerdo de uma atribuição. Significa "pegar todos os elementos restantes
Array
do lado direito":E por último, mas não menos importante, as atribuições paralelas podem ser aninhadas usando parênteses:
Quando você
return
a partir de um método ounext
oubreak
de um bloco, Ruby vai tratar este tipo-de como o lado direito de uma atribuição, de modoA propósito, isso também funciona em listas de parâmetros de métodos e blocos (com métodos sendo mais estritos e blocos menos estritos):
Blocos sendo "menos rígidos" é, por exemplo, o que faz
Hash#each
funcionar. Na verdade, éyield
um único elemento de doisArray
de de chave e valor para o bloco, mas geralmente escrevemosao invés de
fonte
tadman e Jörg W Mittag conhecem Ruby melhor do que eu, e suas respostas não estão erradas, mas eu não acho que eles estão respondendo o que OP queria saber. Acho que a questão não estava clara. No meu entendimento, o que OP queria perguntar não tem nada a ver com o retorno de vários valores.
A verdadeira questão é, quando você deseja trocar os valores de duas variáveis
a
eb
(ou duas posições em uma matriz como na questão original), por que não é necessário usar uma variável temporaltemp
como:mas pode ser feito diretamente como:
A resposta é que na atribuição múltipla, todo o lado direito é avaliado antes da atribuição de todo o lado esquerdo e não é feito um por um. Então
a, b = b, a
não é equivalente aa = b; b = a
.Avaliar primeiro todo o lado direito antes da atribuição é uma necessidade que decorre do ajuste quando os dois lados
=
têm diferentes números de termos, e a descrição de Jörg W Mittag pode estar indiretamente relacionada a isso, mas essa não é a questão principal.fonte
As matrizes são uma boa opção se você tiver apenas alguns valores. Se você quiser vários valores de retorno sem precisar saber (e ser confundido) a ordem dos resultados, uma alternativa seria retornar um Hash que contenha quaisquer valores nomeados que você deseja.
por exemplo
fonte