2013-03-01 19 views
8

Ich habe eine Klasse, die wie folgt aussieht:Gibt es eine Möglichkeit, in Scala eine Teilmenge von Typparametern anzugeben, um den Rest abzuleiten?

class X[A <: Throwable, B, C](b: B, c: C) 

A, B und C geschlossen werden kann, so kann ich es nur mit instanziiert:

val x = new X(3, 4) 

die mir ein X gibt [Nichts, Int, Int] - oft was ich will.

aber ich möchte manchmal angeben, dass A etwas anderes als Nothing sein soll (sagen Sie AssertionError). Ist dies möglich, ohne auch die Angabe B und C. Ich stellte mir Syntax entlang der Linien von:

val x = new X[AssertionError](3, 4) 
val x = new X[AssertionError, _, _](3, 4) 
val x = new X[AssertionError,,](3, 4) 

aber offensichtlich funktioniert das nicht.

Gibt es eine Syntax dafür, oder kann ich das gleiche Ergebnis erzielen?

Antwort

3

Wenn Sie nicht von terse hardcore Syntax Angst haben, könnten Sie type lamdas hierfür verwenden möchten:

Welcome to Scala version 2.10.0-20121205-235900-18481cef9b (OpenJDK 64-Bit Server VM, Java 1.7.0_15). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> case class X[A <: Throwable, B, C](b: B, c: C) 
defined class X 

scala> type P[A,B] = ({type l[a,b] = X[AssertionError, a, b]})#l[A,B] 
defined type alias P 

scala> val x = new P(1,2) 
x: X[AssertionError,Int,Int] = X(1,2) 

Noch eine Art Alias ​​definieren, wie Frank S. Thomas vorgeschlagen, ist ein Weg zu gehen Hier.

+0

Und das Tolle daran ist, dass Sie immer noch explizit die Rest Typ Parameter festlegen können: 'val x = new P [Int, Lang] (1, 2)' kompiliert und korrekt Typ sein, wie 'X [AssertionError, Int, Long] 'anstelle des Standard-' X [AssertionError, Int, Int] ' –

+1

Es sieht so aus, als ob Sie eine Snapshot-Version von Scala 2.10 verwenden ... Vielleicht möchten Sie die endgültige Version 2.10.0 ! –

+0

Ich frage mich, ob es irgendwelche praktischen Unterschiede zwischen Ihrem Typ-Alias ​​'P' und meinem' XAssertionError' gibt. Sind sie nicht für alle praktischen Zwecke identisch? –

3

Sie könnten eine Art Alias, wo Ihre erste Typ-Parameter festgelegt sind zu AssertionError definieren:

scala> class X[A <: Throwable, B, C](b: B, c: C) 
defined class X 

scala> type XAssertionError[B, C] = X[AssertionError, B, C] 
defined type alias XAssertionError 

scala> val x = new XAssertionError(3,4) 
x: X[java.lang.AssertionError,Int,Int] = [email protected] 
+0

+1. Das ist cool, aber wenn ich an jedem Verwendungsort einen anderen Ausnahmetyp festlege, ist es ein bisschen ausführlich. – Draemon

+0

Das ist ziemlich genau das, was ich vorgeschlagen habe, ein Kommentar anstelle einer separaten Lösung hinzuzufügen, wäre eine nette Geste gewesen. Ich werde meine Antwort aus Gründen der Klarheit löschen ... – bluenote10

+0

@ bluenote10 Sie haben eine Unterklasse vorgeschlagen, die schwerer ist (zur Laufzeit vorhanden). Der Typ Alias-Lösung ist besonders sauber (wird zur Kompilierzeit aufgelöst) – Draemon

4

Meine Hauptanliegen dieser am Punkt der Verwendung leicht machen sollten (ich würde es vorziehen, nicht zu definieren, haben neue Typen für jede Verwendung, da die Ausnahmetypen oft unterschiedlich sind). Ich fand, dass ich die Begleiter Objekt Fabrik eine Zwischen Fabrik verwenden:

class X[A <: Throwable, B, C](b: B, c: C) { 
} 

trait XFactory[A <: Throwable] { 
    def apply[B, C](b: B, c: C): X[A, B, C] 
} 

object X { 
    def apply[A <: Throwable: Manifest](): XFactory[A] = { 
    new XFactory[A] { 
     override def apply[B, C](b: B, c: C): X[A, B, C] = { 
     new X(b, c) 
     } 
    } 
    } 
} 

val x = X[AssertionError].apply(3,3) 

Der einzige Nachteil ich sehen kann, ist, dass Sie die „Übernehmen“ zu buchstabieren haben.

3

Hier ist meine Lösung:

scala> class X[A <: Throwable, B, C](b: B, c: C) 
defined class X 

scala> class Builder[A <: Throwable] { 
    | def apply[B, C](b: B, c: C) = new X[A,B,C](b,c) 
    | } 
defined class Builder 

scala> def X[A <: Throwable]: Builder[A] = new Builder[A] 
X: [A <: Throwable]=> Builder[A] 

scala> val x = X[AssertionError](3, 4) 
x: X[AssertionError,Int,Int] = [email protected] 
+0

Wirklich eine großartige Lösung, kurz, funktioniert super. – Suma

1

Sie könnten einen Konstruktor mit einem Standardargument nur definieren.

scala> class X[A <: Throwable, B, C](b: B, c: C, clz:Class[_ <: A] = classOf[Nothing]) 
defined class X 

scala> new X(1,2) 
res0: X[Nothing,Int,Int] = [email protected] 

scala> new X(1,2, classOf[AssertionError]) 
res1: X[AssertionError,Int,Int] = [email protected] 
Verwandte Themen