W jakich sytuacjach preferowane są typy abstrakcyjne nad parametrami typu?Typy abstrakcyjne a parametry typu
Odpowiedz
Aby dodać do moich previous answer on Abstract type vs. parameters, masz również JESSE EICHAR's recent blog post (2010, 3 maja) podkreślając kilka kluczowych różnic:
trait C1[A] {
def get : A
def doit(a:A):A
}
trait C2 {
type A
def get : A
def doit(a:A):A
}
W C2
przypadku parametr jest „pochowany” (jako wewnętrzny abstrakcyjny rodzaj).
(z wyjątkiem, jak retronim stawia go, nie jest rzeczywiście pochowany, patrz niżej)
Podczas gdy z typu rodzajowego parametr jest wyraźnie wymienione, pomagając inne wyrażenia wiedzieć, jakiego rodzaju mają się stosować
Tak (C1: parametr):
//compiles
def p(c:C1[Int]) = c.doit(c.get)
To kompiluje, ale naraża się wyraźnie 'A
' typ, którego chcesz użyć.
i (C2: Abstract typ):
// doesn't compile
def p2(c:C2) = c.doit(c.get)
<console>:6: error: illegal dependent method type
def p2(c:C2) = c.doit(c.get)
^
To nie kompiluje ponieważ „A
” nigdy nie jest wymienione w definicji P2, tak doit
nie wie, w rodzaju kompilacji to, co ma, aby powrócić .
Podczas korzystania abstrakcyjny typ i chcąc uniknąć wszelkich „typ wycieku” do interfejsu (czyli chcąc narażać co A
'faktycznie jest), można określić typ bardzo ogólny jako powrót do p2 :
// compiles because the internals of C2 does not leak out
def p(c:C2):Unit = c.doit(c.get)
Albo można "naprawić" tego typu bezpośrednio w doit
funkcję:
def doit(a:A):Int
zamiast def doit(a:A):A
, co oznacza:
def p2(c:C2) = c.doit(c.get)
skompiluje (nawet jeśli p2 nie wspomina o żadnych typ zwracany)
Finally (retronym „s komentarz) można określić A
jawnie przez rafinacji C2 abstrakcyjnego parametru:
scala> def p2(c:C2 { type A = Int }): Int = c.doit(c.get)
p2: (c: C2{type A = Int})Int
albo przez dodawanie parametru typu (i dopracowywanie typu abstrakcyjnego C2 za pomocą!)
scala> def p2[X](c:C2 { type A = X }): X = c.doit(c.get)
p2: [X](c: C2{type A = X})X
Więc abstrakcyjne są zalecane:
- Gdy chcesz ukryć dokładnej definicji członka typu z kodu klienckiego, użyj abstrakcyjny typ jak w
C2
(ale być nieufny wobec definicji funkcji przy użyciuC2
) - Gdy chcesz zastąpić typ współrzędnie w podklasach
C2
, użyj abstrakcyjny typ (z ograniczonego typu abstrakcji) - Gdy chcesz mieszać w definicjach tych
C2
typów poprzez cech, użyj abstrakcyjny typ (nie trzeba „A
” do czynienia podczas mieszania zC2
klasa: wymieszać tylkoC2
)
do reszty, gdzie proste typ instancji potrzeba, użyć parametrów.
(jeśli wiesz, że bez rozszerzenia będą potrzebne, ale nadal trzeba obsługiwać kilka rodzajów: to jakie typy parametrów są za)
retronym dodaje:
The główne różnice są
- wariancji:
C2
może być tylko niezmienna wA
, - sposób, że członkowie typu mogą być selektywnie nadpisane w podtyp (podczas gdy parametry muszą być zapisane redeclared i przekazywana nadtypu)
(jak illustrating here:
trait T1 {
type t
val v: t
}
trait T2 extends T1 {
type t <: SomeType1
}
trait T3 extends T2 {
type t <: SomeType2 // where SomeType2 <: SomeType1
}
class C extends T3 {
type t = Concrete // where Concrete <: SomeType2
val v = new Concrete(...)
}
)
To nie jest naprawdę pochowany: 'def p2 (c: C2 {typ A = Int}): Int = c.doit (c.get)'. Lub: def p2 [X] (c: C2 {typ A = X}): X = c.doit (c.get) '. Głównymi różnicami są wariancja ("C2" może być tylko niezmienna w "A") oraz sposób, w jaki członkowie typu mogą być selektywnie nadpisywane w podtypie, podczas gdy parametry typu muszą być redeclared i przekazywane do nadtypu. – retronym
@retronym: * "Główne różnice to wariancja ... i sposób, w jaki członkowie typu mogą zostać selektywnie zmienione" * Czy to oznacza, że wszystko, co jest możliwe do zrobienia z jednym z nich, można zrobić z drugim? Z wyjątkiem dwóch aspektów, o których wspomniałeś. Jedyną różnicą jest składnia? – Lii
- 1. Parametry typu mieszania i typy abstrakcyjne w scala
- 2. Parametry typu a typy członków w Scali
- 3. cechy i abstrakcyjne typy
- 4. Właściwości abstrakcyjne lub parametry konstruktora podstawowego?
- 5. Opcjonalne parametry typu niesystemowego
- 6. Typy danych klas typu
- 7. Variadic parametry szablonu jednego określonego typu
- 8. Parametry AsyncTask doInBackground a parametry konstruktora
- 9. dla typu szablonu funkcja Parametry
- 10. Typy generyczne Java typu erasure
- 11. Parametry typu zagnieżdżonego w definicji typu
- 12. Parametry typu i poszerzenie numeryczne
- 13. Java wildcards vs parametry typu
- 14. Typy generyczne a Klasa abstrakcyjna/Interfejsy
- 15. Fabryczne/abstrakcyjne zamieszanie fabryczne
- 16. Parametry metody a obiekt parametrów
- 17. Parametry dziedziczenia i typu z Traversalable
- 18. f # Statycznie rozdzielone typy w elementach typu
- 19. Jak modelować typy enum bezpieczne dla typu?
- 20. Typy ogólne z parametrem typu w C#
- 21. Dlaczego nie abstrakcyjne pola?
- 22. Metody abstrakcyjne NSURL Protococol
- 23. Czy abstrakcyjne fabryki używają "nowego"?
- 24. W jaki sposób dopasowujesz się do typu "A a b"?
- 25. Klasy abstrakcyjne w kontenerach standardowych
- 26. parametry szablonu Szablon bez podania wewnętrzną typu
- 27. JAXB i klasy abstrakcyjne
- 28. Niekompletne typy jak parametry funkcji i zwracane wartości
- 29. Jak zdobyć PublicKey z AsymmetricCipherKeyPair, a nie parametry publickeycipher?
- 30. rodzajowych Java, rozszerzone rodzajowych i klasy abstrakcyjne
Czy nie jest to już omówione na http://stackoverflow.com/questions/1154571/scala-abstract-types-vs-generics/1154727#1154727? – VonC
@VonC: Widziałem tę odpowiedź, ale nie uznałem jej za satysfakcjonującą. –
Próbuję zilustrować to poniżej, z niedawnym wpisem na blogu od Jessego EICHARA. – VonC