Definiciones de clase:
val
o var
puede omitirse de los parámetros de la clase, lo que hará que el parámetro sea privado.
Agregar var o val hará que sea público (es decir, se generan descriptores de acceso y mutadores de método).
{}
se puede omitir si la clase no tiene cuerpo, es decir,
class EmptyClass
Creación de instancias de clase:
Los parámetros genéricos se pueden omitir si el compilador puede inferirlos. Sin embargo, tenga en cuenta que si sus tipos no coinciden, el parámetro de tipo siempre se infiere para que coincida. Entonces, sin especificar el tipo, es posible que no obtenga lo que espera, es decir, dado
class D[T](val x:T, val y:T);
Esto le dará un error de tipo (Int encontrado, Cadena esperada)
var zz = new D[String]("Hi1", 1) // type error
Considerando que esto funciona bien:
var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}
Porque el parámetro de tipo, T, se infiere como el supertipo menos común de los dos: Cualquiera.
Definiciones de funciones:
=
se puede descartar si la función devuelve Unit (nada).
{}
para el cuerpo de la función se puede descartar si la función es una sola declaración, pero solo si la declaración devuelve un valor (necesita el =
signo), es decir,
def returnAString = "Hi!"
pero esto no funciona:
def returnAString "Hi!" // Compile error - '=' expected but string literal found."
El tipo de retorno de la función se puede omitir si se puede inferir (un método recursivo debe tener especificado su tipo de retorno).
()
se puede descartar si la función no acepta ningún argumento, es decir,
def endOfString {
return "myDog".substring(2,1)
}
que por convención está reservado para métodos que no tienen efectos secundarios, más sobre eso más adelante.
()
en realidad no se descarta per se al definir un parámetro de paso por nombre , pero en realidad es una notación bastante diferente semánticamente, es decir,
def myOp(passByNameString: => String)
Dice que myOp toma un parámetro de paso por nombre, lo que da como resultado una cadena (es decir, puede ser un bloque de código que devuelve una cadena) en lugar de los parámetros de función,
def myOp(functionParam: () => String)
que dice myOp
toma una función que tiene cero parámetros y devuelve una cadena.
(Eso sí, los parámetros de paso por nombre se compilan en funciones; solo hace que la sintaxis sea más agradable).
()
se puede eliminar en la definición del parámetro de función si la función solo toma un argumento, por ejemplo:
def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }
Pero si toma más de un argumento, debe incluir el ():
def myOp2(passByNameString:(Int, String) => String) { .. }
Declaraciones:
.
se puede eliminar para usar la notación de operador, que solo se puede usar para operadores infijos (operadores de métodos que toman argumentos). Vea la respuesta de Daniel para obtener más información.
.
también se puede eliminar para funciones postfijas lista cola
()
se puede eliminar para la lista de operadores de postfix.
()
no se puede utilizar con métodos definidos como:
def aMethod = "hi!" // Missing () on method definition
aMethod // Works
aMethod() // Compile error when calling method
Porque esta notación está reservada por convención para métodos que no tienen efectos secundarios, como List # tail (es decir, la invocación de una función sin efectos secundarios significa que la función no tiene ningún efecto observable, excepto por su valor de retorno).
()
se puede eliminar para la notación del operador al pasar un solo argumento
()
puede ser necesario utilizar operadores de sufijo que no están al final de una declaración
()
puede ser necesario para designar declaraciones anidadas, fines de funciones anónimas o para operadores que toman más de un parámetro
Al llamar a una función que toma una función, no puede omitir el () de la definición de función interna, por ejemplo:
def myOp3(paramFunc0:() => String) {
println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work
Cuando llama a una función que toma un parámetro por nombre, no puede especificar el argumento como una función anónima sin parámetros. Por ejemplo, dado:
def myOp2(passByNameString:Int => String) {
println(passByNameString)
}
Debes llamarlo como:
myOp("myop3")
o
myOp({
val source = sourceProvider.source
val p = myObject.findNameFromSource(source)
p
})
pero no:
myOp(() => "myop3") // Doesn't work
En mi opinión, el uso excesivo de tipos de retorno descartables puede ser perjudicial para la reutilización del código. Solo mire las especificaciones para ver un buen ejemplo de legibilidad reducida debido a la falta de información explícita en el código. La cantidad de niveles de direccionamiento indirecto para determinar realmente cuál es el tipo de variable puede ser una locura. Con suerte, mejores herramientas pueden evitar este problema y mantener nuestro código conciso.
(De acuerdo, en la búsqueda para compilar una respuesta más completa y concisa (si me he perdido algo, o he recibido algo incorrecto / inexacto, por favor comente), agregué al principio de la respuesta. Tenga en cuenta que esto no es un idioma especificación, por lo que no estoy tratando de hacerlo exactamente académicamente correcto, sino más bien como una tarjeta de referencia).