Notação de infixo Scala

12

É possível chamar um método usando notação infix?

Por exemplo, em Haskell, eu poderia escrever a seguinte função:

x `isAFactorOf` y = x % y == 0

e depois use-o como:

if 2 `isAFactorOf` 10 ...

O que, em alguns casos, permite código muito legível. Existe algo semelhante a isso possível em Scala? Eu procurei por "notação de infixo Scala", mas esse termo parece significar algo diferente em Scala.

Carcinigenicado
fonte

Respostas:

15

A partir da versão 2.10, o Scala introduziu classes implícitas para lidar com esse problema com precisão.

Isso executará uma conversão implícita em um determinado tipo em uma classe agrupada, que pode conter seus próprios métodos e valores.

No seu caso específico, você usaria algo como isto:

implicit class RichInt(x: Int) {
  def isAFactorOf(y: Int) = x % y == 0
}

2.isAFactorOf(10)
// or, without dot-syntax
2 isAFactorOf 10

Observe que, quando compilado, isso acabará encaixotando nosso valor bruto em a RichInt(2). Você pode contornar isso declarando seu RichInt como uma subclasse de AnyVal:

implicit class RichInt(val x: Int) extends AnyVal { ... }

Isso não causa boxe, mas é mais restritivo do que uma classe implícita típica. Ele pode conter apenas métodos, não valores ou estado.

KChaloux
fonte
2
Você provavelmente deve mencionar que classes implícitas não podem ser de nível superior; portanto, a classe implícita precisará ser definida localmente.
Carcigenicate
3

Essencialmente, no Scala, você não pode chamar uma função de maneira infix, mas pode definir um método em um tipo, no qual o argumento esquerdo pode ser convertido implicitamente. Portanto, para o seu exemplo, você pode definir uma classe que possui o método isAFactorOf (usando um Int) e indicar que um Int pode ser implicitamente convertido em uma instância dessa classe.

Se você olhar para esta resposta /programming//a/3119671 para outra pergunta, verá a sintaxe no Scala que funciona de maneira equivalente.

eques
fonte
Vale a pena destacar que as novas versões do Scala tem uma construção explícita para isso, que a resposta vinculado não endereço: implicit class RichInt(i: Int) { def square() = i * i }.
KChaloux