Definicje klas:
val
lub var
może zostać pominięty w parametrach klasy, co spowoduje, że parametr stanie się prywatny.
Dodanie var lub val spowoduje, że stanie się on publiczny (to znaczy, że zostaną wygenerowane metody dostępu i mutatory).
{}
można pominąć, jeśli klasa nie ma treści, to znaczy
class EmptyClass
Instancja klasy:
Parametry ogólne można pominąć, jeśli mogą być wywnioskowane przez kompilator. Należy jednak pamiętać, że jeśli typy nie są zgodne, parametr typu jest zawsze pobierany, aby był zgodny. Tak więc bez określenia typu możesz nie otrzymać tego, czego oczekujesz - to znaczy danego
class D[T](val x:T, val y:T);
To da ci błąd typu (znaleziono Int, oczekiwany ciąg)
var zz = new D[String]("Hi1", 1) // type error
Podczas gdy to działa dobrze:
var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}
Ponieważ parametr typu, T, jest wywnioskowany jako najmniej powszechny nadtyp z dwóch - Any.
Definicje funkcji:
=
można usunąć, jeśli funkcja zwraca Jednostka (nic).
{}
ponieważ treść funkcji może zostać usunięta, jeśli funkcja jest pojedynczą instrukcją, ale tylko wtedy, gdy instrukcja zwraca wartość (potrzebujesz =
znaku), to znaczy
def returnAString = "Hi!"
ale to nie działa:
def returnAString "Hi!" // Compile error - '=' expected but string literal found."
Zwracany typ funkcji można pominąć, jeśli można go wywnioskować (metoda rekurencyjna musi mieć określony typ zwracania).
()
można porzucić, jeśli funkcja nie przyjmuje żadnych argumentów, to znaczy
def endOfString {
return "myDog".substring(2,1)
}
który umownie jest zarezerwowany dla metod, które nie mają skutków ubocznych - o tym później.
()
nie jest w rzeczywistości pomijana jako taka podczas definiowania paramentera pass by name , ale w rzeczywistości jest to całkiem inna semantycznie notacja, to znaczy
def myOp(passByNameString: => String)
Mówi, że myOp przyjmuje parametr przekazywany przez nazwę, co skutkuje ciągiem znaków (to znaczy może być blokiem kodu, który zwraca ciąg), w przeciwieństwie do parametrów funkcji,
def myOp(functionParam: () => String)
która mówi, że myOp
przyjmuje funkcję, która ma zero parametrów i zwraca String.
(Pamiętaj, parametry przekazywania przez nazwę są kompilowane w funkcje; to po prostu poprawia składnię).
()
można pominąć w definicji parametru funkcji, jeśli funkcja przyjmuje tylko jeden argument, na przykład:
def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }
Ale jeśli wymaga więcej niż jednego argumentu, musisz dołączyć ():
def myOp2(passByNameString:(Int, String) => String) { .. }
Sprawozdania:
.
można zrezygnować z używania notacji operatorów, która może być używana tylko dla operatorów wrostków (operatorów metod pobierających argumenty). Zobacz odpowiedź Daniela, aby uzyskać więcej informacji.
.
może być również usunięty z listy funkcji postfiksowych
()
można usunąć dla operatorów postfiksowych list.tail
()
nie można używać z metodami zdefiniowanymi jako:
def aMethod = "hi!" // Missing () on method definition
aMethod // Works
aMethod() // Compile error when calling method
Ponieważ ta notacja jest przez konwencję zarezerwowana dla metod, które nie mają skutków ubocznych, takich jak List # tail (czyli wywołanie funkcji bez skutków ubocznych oznacza, że funkcja nie ma żadnego obserwowalnego efektu, z wyjątkiem wartości zwracanej).
()
można porzucić dla notacji operatora podczas przekazywania pojedynczego argumentu
()
może być wymagane użycie operatorów postfiksowych, które nie znajdują się na końcu instrukcji
()
może być wymagane wyznaczenie zagnieżdżonych instrukcji, końców funkcji anonimowych lub operatorów, które przyjmują więcej niż jeden parametr
Podczas wywoływania funkcji, która przyjmuje funkcję, nie można pominąć () w definicji funkcji wewnętrznej, na przykład:
def myOp3(paramFunc0:() => String) {
println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work
Podczas wywoływania funkcji, która przyjmuje parametr typu „by-name”, nie można określić argumentu jako funkcji anonimowej bez parametrów. Na przykład, biorąc pod uwagę:
def myOp2(passByNameString:Int => String) {
println(passByNameString)
}
Musisz to nazwać:
myOp("myop3")
lub
myOp({
val source = sourceProvider.source
val p = myObject.findNameFromSource(source)
p
})
ale nie:
myOp(() => "myop3") // Doesn't work
IMO, nadużywanie upuszczania typów zwracanych może być szkodliwe dla ponownego wykorzystania kodu. Wystarczy spojrzeć na specyfikację, aby znaleźć dobry przykład ograniczonej czytelności z powodu braku wyraźnych informacji w kodzie. Liczba poziomów pośrednich, aby faktycznie dowiedzieć się, jaki jest typ zmiennej, może być szalona. Miejmy nadzieję, że lepsze narzędzia mogą zapobiec temu problemowi i zachować zwięzły kod.
(OK, w celu skompilowania pełniejszej, zwięzłej odpowiedzi (jeśli coś przeoczyłem lub dostałem coś złego / niedokładnego, proszę o komentarz), dodałem na początku odpowiedzi. Pamiętaj, że to nie jest język specyfikacji, więc nie staram się, aby było dokładnie poprawne naukowo - po prostu bardziej jak karta referencyjna.)