2015-04-28 18 views
10

Mam problem z następującą hierarchią w Scala:rodzajowych Scala i dziedziczenie

class ScalaGenericTest { 
    def getValue[A, B <: Abstract[A]](clazz: B): A = clazz.a 

    def call: String = { 
    val sub: Subclass = new Subclass 
    getValue(sub) 
    } 
} 

class Subclass extends Abstract[String] { 
    def a: String = "STRING" 
} 

abstract class Abstract[A] { 
    def a: A 
} 

Kompilator nie wydają się być zdolne do wiązania rodzajowego parametr a w wywołaniu funkcji getValue - I sądzę, że powinien być w stanie wywnioskować to z definicji Subklasy. Błąd kompilacji jest następujący:

wywnioskować argumentów typu [Nic Podklasa] nie są zgodne z granicami parametru Typ Metoda getValue w [A, B <: Streszczenie [A]]

To działa, jeśli I jawnie przekazać ogólnych typów argumentów metody, tj. getValue[String,Subclass](sub), ale na pewno kompilator powinien móc wywnioskować to?

tej samej hierarchii działa dobrze w Javie:

public class JavaGenericTest { 

    public <T,U extends Abstract<T>> T getValue(U subclass) { 
     return subclass.getT(); 
    } 

    public String call(){ 
     Subclass sub = new Subclass(); 
     return getValue(sub); 
    } 

    private static class Subclass extends Abstract<String> { 
     String getT(){ 
      return "STRING"; 
     } 
    } 

    private static abstract class Abstract<T> { 
     abstract T getT(); 
    } 
} 

Jestem całkiem nowy Scala więc pewnie niektórzy subtelność, że mi brakuje.

Z góry dziękuję za pomoc!

Odpowiedz

9

Jest to ograniczenie w wnioskowaniu typu Scala. Problem został opisany w SI-2272 (w tym przykładzie użyto implicits, ale ten sam błąd występuje podczas używania go jawnie). Został zamknięty, ponieważ nie naprawi.

W tym numerze Adriaan Moors zaleca unikanie ograniczeń, które mają zmienne typu po obu stronach. to znaczy. B <: Abstract[A]. Łatwym obejściem byłoby całkowite uniknięcie drugiego parametru.

def getValue[A](clazz: Abstract[A]): A = clazz.a 

scala> val sub = new Subclass 
sub: Subclass = [email protected] 

scala> getValue(sub) 
res11: String = STRING 

Dodatkowo Adriaan umieszczono również sposób korzystania z niejawnego <:< jako inny obejść. Aby umieścić go w kontekście swojej przykład to będzie wyglądać:

def getValue[A, B](b: B)(implicit ev: B <:< Abstract[A]): B = b.a 

Gdzie instancją <:< jest pośrednio poprzez Predef.

+0

Można również użyć niejawny widok od parametru rodzajowego z 'B <% Streszczenie [A]'. Myślę, że może to być przestarzałe, ale ukryty argument, jaki on tworzy, jest wystarczającym dowodem na wnioskowanie o typie. –

+0

Świetna odpowiedź. Wziąłem pod uwagę domyślne podejście do argumentów, ale nie widziałem dobrego powodu, dla którego oryginał nie działał. Zobacz ograniczenia przy użyciu <% zdecydowanie zostały wycofane. – paulyb

1

jako dodatek do Justina i odpowiedzi m-Z, w inny sposób, aby podobną deklarację utrzymując dwa parametry Typ:

def getValue[A, B](clazz: B)(implicit evidence: B <:< Abstract[A]): A = clazz.a 
3

mam w jednym czasie za ten sam problem. I stworzył duży dorozumiany dowód do pokonania. Potem przypadkowo zajrzeć do kolekcji scala Dokumentacja API i znalazł rozwiązanie: http://www.scala-lang.org/api/2.11.4/index.html#scala.collection.generic.GenericTraversableTemplate

class ScalaGenericTest { 
    def getValue[A, B[X] <: Abstract[X]](clazz: B[A]): A = clazz.a 

    def call: String = { 
    val sub: Subclass = new Subclass 
    getValue(sub) 
    } 
} 

class Subclass extends Abstract[String] { 
    def a: String = "STRING" 
} 

abstract class Abstract[A] { 
    def a: A 
}