Definições de classe:
val
ou var
pode ser omitido dos parâmetros de classe, o que tornará o parâmetro privado.
Adicionar var ou val fará com que seja público (isto é, acessadores e modificadores de método são gerados).
{}
pode ser omitido se a classe não tiver corpo, ou seja,
class EmptyClass
Instanciação de classe:
Os parâmetros genéricos podem ser omitidos se puderem ser inferidos pelo compilador. No entanto, observe que se seus tipos não corresponderem, o parâmetro de tipo sempre será inferido para que corresponda. Portanto, sem especificar o tipo, você pode não obter o que espera - isto é, dado
class D[T](val x:T, val y:T);
Isso lhe dará um erro de tipo (Int encontrado, String esperada)
var zz = new D[String]("Hi1", 1) // type error
Considerando que isso funciona bem:
var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}
Porque o parâmetro de tipo, T, é inferido como o supertipo menos comum dos dois - Qualquer.
Definições de função:
=
pode ser descartado se a função retornar Unit (nada).
{}
pois o corpo da função pode ser eliminado se a função for uma única instrução, mas apenas se a instrução retornar um valor (você precisa do =
sinal), ou seja,
def returnAString = "Hi!"
mas isso não funciona:
def returnAString "Hi!" // Compile error - '=' expected but string literal found."
O tipo de retorno da função pode ser omitido se puder ser inferido (um método recursivo deve ter seu tipo de retorno especificado).
()
pode ser descartado se a função não receber nenhum argumento, ou seja,
def endOfString {
return "myDog".substring(2,1)
}
que por convenção é reservado para métodos que não têm efeitos colaterais - mais sobre isso mais tarde.
()
não é descartado per se ao definir um parâmetro de passagem por nome , mas é na verdade uma notação semanticamente diferente, isto é,
def myOp(passByNameString: => String)
Diz que myOp usa um parâmetro de passagem por nome, que resulta em uma String (ou seja, pode ser um bloco de código que retorna uma string) em vez de parâmetros de função,
def myOp(functionParam: () => String)
que diz que myOp
pega uma função que tem zero parâmetros e retorna uma String.
(Lembre-se, os parâmetros passados por nome são compilados em funções; isso apenas torna a sintaxe mais agradável.)
()
pode ser descartado na definição do parâmetro da função se a função tiver apenas um argumento, por exemplo:
def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }
Mas se for necessário mais de um argumento, você deve incluir o ():
def myOp2(passByNameString:(Int, String) => String) { .. }
Afirmações:
.
pode ser descartado para usar a notação de operador, que só pode ser usada para operadores infixos (operadores de métodos que recebem argumentos). Veja a resposta de Daniel para mais informações.
.
também pode ser descartado para o final da lista de funções postfix
()
pode ser descartado para operadores postfix list.tail
()
não pode ser usado com métodos definidos como:
def aMethod = "hi!" // Missing () on method definition
aMethod // Works
aMethod() // Compile error when calling method
Porque essa notação é reservada por convenção para métodos que não têm efeitos colaterais, como List # tail (ou seja, a invocação de uma função sem efeitos colaterais significa que a função não tem efeito observável, exceto por seu valor de retorno).
()
pode ser descartado para notação de operador ao passar um único argumento
()
pode ser necessário usar operadores postfix que não estão no final de uma instrução
()
pode ser necessário para designar instruções aninhadas, fins de funções anônimas ou para operadores que usam mais de um parâmetro
Ao chamar uma função que assume uma função, você não pode omitir o () da definição de função interna, por exemplo:
def myOp3(paramFunc0:() => String) {
println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work
Ao chamar uma função que usa um parâmetro por nome, você não pode especificar o argumento como uma função anônima sem parâmetro. Por exemplo, dado:
def myOp2(passByNameString:Int => String) {
println(passByNameString)
}
Você deve chamá-lo como:
myOp("myop3")
ou
myOp({
val source = sourceProvider.source
val p = myObject.findNameFromSource(source)
p
})
mas não:
myOp(() => "myop3") // Doesn't work
IMO, o uso excessivo de tipos de retorno de descarte pode ser prejudicial para o código a ser reutilizado. Basta olhar a especificação para um bom exemplo de legibilidade reduzida devido à falta de informações explícitas no código. O número de níveis de indireção para realmente descobrir qual é o tipo de uma variável pode ser louco. Esperançosamente, ferramentas melhores podem evitar esse problema e manter nosso código conciso.
(OK, na busca para compilar uma resposta mais completa e concisa (se eu perdi alguma coisa ou entendi algo errado / impreciso, por favor, comente), adicionei no início da resposta. Observe que esta não é uma linguagem especificação, portanto, não estou tentando torná-la exatamente academicamente correta - apenas mais como um cartão de referência.)