Você provavelmente está familiarizado com a seguinte abreviação de Ruby ( a
é uma matriz):
a.map(&:method)
Por exemplo, tente o seguinte no irb:
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
A sintaxe a.map(&:class)
é um atalho para a.map {|x| x.class}
.
Leia mais sobre esta sintaxe em " O que map (&: name) significa em Ruby? ".
Por meio da sintaxe &:class
, você está fazendo uma chamada de método class
para cada elemento do array.
Minha pergunta é: você pode fornecer argumentos para a chamada do método? E se sim, como?
Por exemplo, como você converte a seguinte sintaxe
a = [1,3,5,7,9]
a.map {|x| x + 2}
para a &:
sintaxe?
Não estou sugerindo que a &:
sintaxe seja melhor. Estou apenas interessado na mecânica de usar a &:
sintaxe com argumentos.
Presumo que você saiba que +
é um método na classe Integer. Você pode tentar o seguinte no irb:
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
Symbol#with
possa não existir na biblioteca central e definir esse método seja menos destrutivo do que redefinir um método existente, ele ainda está mudando (ou seja, sobrescrevendo) a implementação da classe central da biblioteca ruby. A prática deve ser feita com moderação e muito cuidado. \ n \ n Por favor, considere herdar da classe existente e modificar a classe recém-criada. Isso geralmente atinge resultados comparáveis sem os efeitos colaterais negativos da mudança de classes de rubi.Symbol
classe - não é trivial (se mesmo possível), uma vez que é uma classe central (não temnew
método, por exemplo), e seu uso será complicado (se mesmo possível), o que irá derrotar o propósito do aprimoramento ... se você pode mostrar uma implementação que usa isso e atinge resultados comparáveis - compartilhe!with
método, definacall
. Então você pode fazer coisas como,a.map(&:+.(2))
uma vez queobject.()
usa o#call
método. E enquanto você está nisso, você pode escrever coisas divertidas como:+.(2).(3) #=> 5
- parece meio LISPy, não?Para o seu exemplo pode ser feito
a.map(&2.method(:+))
.Funciona assim: -
2.method(:+)
dá umMethod
objeto. Então&
, na2.method(:+)
verdade, um#to_proc
método de chamada , que é torná-lo umProc
objeto. Em seguida, siga O que você chama de operador &: em Ruby? .fonte
Pry
saídas acima, você pode ver como está funcionando.+
é comutativo.Como a postagem que você vinculou confirma,
a.map(&:class)
não é uma abreviação de,a.map {|x| x.class}
mas paraa.map(&:class.to_proc)
.Isso significa que
to_proc
é chamado em tudo o que segue o&
operador.Então, você pode dar a ele diretamente um
Proc
:Eu sei que muito provavelmente isso vai contra o propósito da sua pergunta, mas não consigo ver outra maneira de contornar isso - não é que você especifique qual método será chamado, você apenas passa algo que responde
to_proc
.fonte
my_proc = Proc.new{|i| i + 1}
,[1,2,3,4].map(&my_proc) => [2,3,4,5]
Resposta curta: Não.
Seguindo a resposta de @rkon, você também pode fazer isso:
fonte
&->(_){_ + 2}
seja menor do que{|x| x + 2}
.Em vez de corrigir você mesmo as classes principais, como na resposta aceita, é mais curto e mais claro usar a funcionalidade da gema Facets :
fonte
Existe outra opção nativa para enumeráveis que é bonita apenas para dois argumentos na minha opinião. a classe
Enumerable
tem o métodowith_object
que retorna outroEnumerable
.Portanto, você pode chamar o
&
operador de um método com cada item e o objeto como argumentos.Exemplo:
Caso queira mais argumentos, deve repetir o processo, mas é feio na minha opinião:
fonte
Não tenho certeza sobre o
Symbol#with
já postado, simplifiquei um pouco e funciona bem:(também usa em
public_send
vez desend
para evitar a chamada de métodos privados, tambémcaller
já é usado pelo ruby, então isso era confuso)fonte