2016-02-24 3 views
1

J'ai un nombre de Builder s qui provient de la bibliothèque dont le code source est généré automatiquement en Java et au-delà de mon contrôle. Ces Builder ne sont pas liés les uns aux autres, mais ils ont un certain nombre de méthodes qui sont structurellement exactement les mêmes. En utilisant le type structurel de Scala, comment puis-je retourner le constructeur pour lui-même?Comment définir le type structurel que la méthode renvoie cette

type StructurallyBuilder = { 
    def setA(xxx): StructurallyBuilder 
    def setB(yyy): StructurallyBuilder 
} 

Quand je veux utiliser Seta et SetB sur le StructurallyBuilder, le compilateur se plaint qu'il ne peut pas résoudre.

+0

Probablement pas si facile: http://stackoverflow.com/questions/3466100/are- recursive-structural-types-not-supported-in-scala-plus? lq = 1 (et suivez les questions liées ici) – Thilo

Répondre

3

Il est pas tout à fait simple, mais je crois que vous pouvez utiliser F-bounded polymorphism pour y parvenir:

type StructurallyBuilder[F <: StructurallyBuilder[F]] = { 
    def setA(xxx: Int): F 
    def setB(yyy: Int): F 
} 

Vous devez garder cette signature complexe lors de la définition des classes ou des méthodes qui prennent ces constructeurs. Par exemple:

def setA[T <: StructurallyBuilder[T]](
    xxx: Int, 
    builder: StructurallyBuilder[T] 
): T = builder.setA(xxx) 

Mais il semble que vous pouvez utiliser ces méthodes normalement:

val bld: a.c.Builder = setA(10, new a.c.Builder()) 
+0

Merci. cela se rapproche. J'ai essayé, mais j'ai une erreur de compilateur quand j'essaie d'appeler 'setA (10, new a.c.Builder())'. Il dit "Type discordance, StructurallyBuilder attendu [NotInferedT], a.c.Builder réel". Si je mets 'setA [acBuilder]' il attend StructurallyBuilder [acBuilder] – Wins

+0

@Wins Hm, ce code fonctionne pour moi: https://gist.github.com/kolmar/f9df191b8130f948550b Il fonctionne aussi pour une classe Java avec le même signature: 'paquet ac; public class Builder { public Constructeur setA (int xxx) {return this; } public Constructeur setB (int yyy) {return this; } } 'Vos objets ne correspondent peut-être pas exactement à la signature? – Kolmar

+0

@Wins Aussi, il semble que Sascha Kolberg a raison. Vous n'avez même pas besoin de polymorphisme lié à F. Voir aussi mon édition. – Kolmar

1

Vous pouvez faire le constructeur réel un paramètre de type de type structural:

import scala.language.reflectiveCalls 
import scala.language.existentials 

type StructurallyBuilder[T <: AnyRef] = AnyRef { 
    def setA(xxx): T 
    def setB(yyy): T 
} 

Voici un petit test que j'ai écrit pour prouver que vous pouvez l'utiliser pour faire circuler n'importe quel constructeur en utilisant 'StructurallyBuilder' comme un type de paramètre:

import scala.language.reflectiveCalls 
import scala.language.existentials 

type StructurallyBuilder[T <: AnyRef] = AnyRef { 
    def setA(a: Int): T 
    def setB(b: String): T 
} 


class Builder1 { 
    var a: Int = _ 
    var b: String = _ 

    def setA(a: Int): Builder1 = { 
    this.a = a 
    this 
    } 

    def setB(b: String): Builder1 = { 
    this.b = b 
    this 
    } 
} 

val builder: StructurallyBuilder[_] = new Builder1 

val b2 = builder.setA(1) 
val b3 = builder.setB("B") 

val builder2 = new Builder1 

def test(builder: StructurallyBuilder[_]): String = { 
    builder.toString 
} 

val t2 = test(builder2) |-> t2: String = [email protected] 
+0

Ça ne marche pas comme j'ai besoin. Ce dont j'ai besoin, c'est que vous puissiez faire quelque chose comme 'builder.setA (1) .setB (" B ")' – Wins

0

pourquoi ne pas utiliser this.type?

type StructurallyBuilder = { 
    def setA(x: Int): this.type 
    def setB(y: Double): this.type 
} 

Exemple de cette utilisation:

object App 
{ 

    class A { 
    def setA(x: Int): this.type = { this } 
    def setB(y: Double): this.type = { this } 
    } 

    type StructurallyBuilder = { 
    def setA(x: Int): this.type 
    def setB(y: Double): this.type 
    } 


    def main(args: Array[String]):Unit = 
    { 
    val a = new A() 
    if (a.isInstanceOf[StructurallyBuilder]) { 
     System.out.println("qqq") 
    } 
    System.out.println(a) 
    } 

} 

Alors, en essayant de courir:

[info] Running X.App 
qqq 
[email protected] 
+1

Parce que 'ceci.type' renverra le type de 'StructurallyBuilder' environnant. Je ne veux pas retourner la classe possédant 'StructurallyBuilder', je veux retourner le' StructurallyBuilder' lui-même – Wins

+0

Nope. this.type pointe vers le constructeur de la structure: – rssh