można określić typ bezpośrednio na metodzie empty
zamiast dodać dodatkowy zestaw parens/szelki i adnotacji typu:
class Bar[A](set: Set[Foo[A]] = Set.empty[Foo[A]])
Jak, dlaczego typ wnioskowanie nie patrz na te pytania :
Aktualizacja:
przepraszam, mój pochopna odpowiedź była daleko. Problem w powyższych postach nie jest tak naprawdę związany z tym problemem. @TravisBrown przedstawił bardzo dobry punkt w swoim komentarzu powyżej. To wydaje się działać na początku:
class Bar[A](set: Set[A] = Set.empty)
Ale jeśli rzeczywiście starają się wywołać konstruktor nie jest on w miejscu użytkowania:
new Bar[Int]
// <console>:9: error: type mismatch;
// found : scala.collection.immutable.Set[Nothing]
// required: Set[Int]
// Note: Nothing <: Int, but trait Set is invariant in type A.
// You may wish to investigate a wildcard type such as `_ <: Int`. (SLS 3.2.10)
// Error occurred in an application involving default arguments.
// new Bar[Int]
Sugeruje to, że kompilator nie wymusza parametr domyślny obowiązuje dla wszystkich A
, tylko dla niektórych A
. Prawdopodobnie popełnił takiego wyboru, więc można zrobić coś takiego:
scala> case class MyClass[T](set: Set[T] = Set(0))
defined class MyClass
scala> MyClass() // defaults to MyClass[Int]
res0: MyClass[Int] = MyClass(Set(0))
scala> MyClass(Set('x)) // but I can still use other types manually
res1: MyClass[Symbol] = MyClass(Set('x))
Jednakże każdy rodzaj zagnieżdżania z parametryzowanego typu niepomyślnym typ kontroli w miejscu deklaracji w konstruktorze:
class Bar[A](set: Set[Option[A]] = Set.empty)
// <console>:7: error: polymorphic expression cannot be instantiated to expected type;
// found : [A]scala.collection.immutable.Set[A]
// required: Set[Option[?]]
// class Bar[A](set: Set[Option[A]] = Set.empty)
The wnioskowanie nie powiedzie się, jeśli parametr typ jest w kowariantna stanowisko:
class Bar[ A ](set: List[Foo[A]] = List.empty) // OK
class Bar[ A ](set: Map[Int,Foo[A]] = Map.empty) // OK (unless you use it)
class Bar[ A ](set: Map[Foo[A],Int] = Map.empty) // BAD
// <console>:8: error: polymorphic expression cannot be instantiated to expected type;
// found : [A, B]scala.collection.immutable.Map[A,B]
// required: Map[Foo[?],Int]
// class Bar[ A ](set: Map[Foo[A],Int] = Map.empty) // BAD
// ^
są to działa, ponieważ kompilator wybiera Nothing
jako współ typ wariantu domyślnie.To działa dobrze dla List
, ale drugi przykład powyżej nie działa, jeśli faktycznie próbujesz go wywołać.
Przyczyną większości tego dziwactwa jest prawdopodobnie sposób, w jaki Scala obsługuje domyślne argumenty. Kompilator automatycznie dodaje dodatkową metodę do obiektu towarzyszącego, a następnie, gdy pominięto argument, kompilator automatycznie dodaje wywołanie metody do nowej metody w obiekcie towarzyszącym, aby zamiast tego wygenerować brakujący argument. Wygląda na to, że wyodrębnienie domyślnego argumentu w metodzie powoduje zerwanie niektórych rzeczy w procesie wnioskowania, które działałyby przy normalnym zadaniu.
Myślę, że większość z tych ustaleń jest dość myląca. Rozumiem, że ważne jest, aby właściwie przetestować parametry domyślne, aby upewnić się, że nie łamią poprawności typu, gdy próbujesz ich użyć!
Nie jest to odpowiedź, ale trzy rzeczy do zapamiętania: możesz chcieć nazwać parametr typu coś innego niż 'A', aby uniknąć pomyłki z (innym)' A' w 'found: [A] scala.collection. immutable.Set [A] 'message; ważnym faktem dotyczącym zarówno 'Set', jak i' Hallo' jest to, że są niezmienne (w przeciwieństwie do 'List'); a twoja ostatnia kompilacja linii prawdopodobnie nie robi tego, co chcesz. –
Podczas gdy 'class Bar [A] (hallo: Hallo [A] = Hallo.apply)' jeśli zmienisz go, aby używał 'Hallo.apply()', to działa dobrze. Powinnaś móc opuścić pareny, więc tutaj musi być naprawdę niezrozumiała. Uważa, że przekazujesz częściowo zastosowaną funkcję 'Hallo.apply' zamiast wywoływać' apply' bez argumentów. (Komunikat o błędzie mówi, że znalazł typ '[A]() Hallo [A]'.) – DaoWen