5 Stimmen

Ist es möglich, generische Rückgabetypen in Scala ähnlich wie C++-Vorlagen zu kodieren?

In C++ kann ich das Folgende tun:

template<typename T, typename V>
struct{
    void operator()(T _1, V _2){
        _2.foo( _1 );
    }
};

die mich willkürlich entscheiden lässt, ein beliebiges Objekt zu verwenden, das eine Methode namens "foo" hat, die einen Typ "T" annimmt, ohne im Voraus den Argumenttyp der Funktion "foo" oder den Rückgabetyp der besagten Funktion anzugeben.

Wenn ich mir Scala anschaue, sehe ich Eigenschaften wie Funktion1 und spiele mit Funktionsdefinitionen wie

def foo[T<:{def foo():Unit}]( arg:T ) = //something
def bar( x:{def foo():Unit} ) = //something
def baz[T,V<:Function1[T,_]]( x:T, y:V ) = y( x )

Ich sehe mich selbst an und denke, warum kann ich nicht dasselbe tun? Warum gibt "baz" ein Any zurück? Kann es nicht den tatsächlichen Rückgabetyp zur Kompilierzeit ableiten? Warum muss ich den Rückgabetyp von "foo" deklarieren, wenn ich ihn vielleicht nicht einmal verwende?

Ich würde gerne Folgendes tun können

def biff[T,V:{def foo( x:T ):Unit}] = //something

o

def boff[T<:{def foo( x:Double ):_}]( y:T ) = y.foo _

Können Sie das tun, oder habe ich etwas übersehen? Oder wenn nicht, warum nicht?

11voto

Aaron Novstrup Punkte 20687

Aktualisierung:

Eigentlich kann man das viel besser, und der Typ-Inferencer se Ihnen helfen:

def boff[T,R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _

Para baz wird die gleiche Technik die Typisierung verbessern:

def baz[T,R,V]( x:T, y:V )(implicit e: V <:< (T => R)) = e(y).apply( x )

scala> baz(1, (i: Int) => i+1) 
res0: Int = 2

Mit Curry kann man es besser machen:

def baz[T,R](x: T)(f: T => R) = f(x)

Erste Lösung:

Der Typ-Inferencer liefert nicht die T Typ für Sie, aber Sie können tun:

class Boff[T] {
   def apply[R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _
}
object boff { 
   def apply[T] = new Boff[T]
}

6voto

Daniel C. Sobral Punkte 290004

Der grundlegende Unterschied zwischen Scala und C++ besteht darin, dass jede Klasse in Scala einmal kompiliert wird und dann als solche für alle von ihr abhängigen Klassen zur Verfügung steht, während eine Template-Klasse in C++ für jede neue Abhängigkeit kompiliert werden muss.

Eine C++-Schablone erzeugt also in der Tat N kompilierte Klassen, während Scala nur eine erzeugt.

Kann es den tatsächlichen Rückgabetyp nicht zur Kompilierzeit ableiten?

Denn dies muss zum Zeitpunkt der Kompilierung der Klasse entschieden werden, der sich von dem Zeitpunkt unterscheiden kann, zu dem ihre Verwendung kompiliert wird.

2voto

Alexey Romanov Punkte 160158

Para foo :

def foo[R,T<:{def foo():R}]( arg:T ) = ...

Im Falle von baz sagen Sie, dass V muss eine Funktion aus T zu irgendeinem Typ. Dieser Typ kann nicht im Ergebnistyp erscheinen: wie könnte man ihn schreiben? Der Compiler kann also nur schlussfolgern, dass der Ergebnistyp Any . Wenn Sie ihm jedoch einen Namen geben, erhalten Sie

scala> def baz[T,R,V<:Function1[T,R]]( x:T, y:V ) = y( x )
baz: [T,R,V <: (T) => R](x: T,y: V)R

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X