2016-02-24 10 views
1

У меня есть номер Builder s, который исходит из библиотеки, исходный код которой автоматически генерируется на Java и не подлежит контролю. Эти Builder s не связаны друг с другом, но они имеют ряд методов, которые являются структурно одинаковыми.Как определить Структурный тип, возвращающий метод

package a.b 

public class Builder { 
    public Builder setA(xxx) {} 
    public Builder setB(yyy) {} 
} 

package a.c 

public class Builder { 
    public Builder setA(xxx) {} 
    public Builder setB(yyy) {} 
} 

Использование структурного типа Scala, как я могу вернуть построитель для себя?

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

Когда я хочу использовать узнающий и SETB на StructurallyBuilder, компилятор жалуется, что не может решить.

+0

Наверное, не так просто: http://stackoverflow.com/questions/3466100/are- рекурсивный-структурный-тип-not-supported-in-scala-больше? lq = 1 (и следуйте связанным вопросам) – Thilo

ответ

3

Это не совсем просто, но я полагаю, вы можете использовать F-bounded polymorphism для достижения этой цели:

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

Вы должны держать эту сложную подпись при определении классов и методов, принимающих эти строители. Например:

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

Но, кажется, вы можете использовать эти методы, как правило:

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

Спасибо. это приближается. Я пробовал, но у меня возникла ошибка компилятора, когда я пытаюсь вызвать 'setA (10, new a.c.Builder())'. В нем говорится: «Тип несоответствия, ожидаемый StructurallyBuilder [NotInferedT], фактический a.c.Builder». Если я поставлю 'setA [acBuilder]', он ожидает StructurallyBuilder [acBuilder] – Wins

+0

@Wins Hm, этот код работает для меня: https://gist.github.com/kolmar/f9df191b8130f948550b Он также работает для класса Java с та же подпись: 'пакет ac; public class Builder { public Builder setA (int xxx) {вернуть это; } public Builder setB (int yyy) {вернуть это; } } 'Возможно, ваши объекты не соответствуют точности подписи? – Kolmar

+0

@Wins Кроме того, кажется, что Саша Кольберг прав. Вам даже не нужен F-ограниченный полиморфизм. Также см. Мое редактирование. – Kolmar

1

Вы можете сделать фактический строитель параметр типа структурного типа:

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

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

Вот небольшое испытание, которое я написал для доказательства того, что вы можете использовать его для передачи любого строителя с использованием «StructurallyBuilder» в качестве типа параметра:

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

Он не работает, как мне нужно. Мне нужно, чтобы вы могли сделать что-то вроде 'builder.setA (1) .setB (" B ")' – Wins

0

почему бы не использовать this.type?

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

Пример такого использования:

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) 
    } 

} 

Затем, пытаясь бежать:

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

Потому что 'this.type' вернет тип окружающего 'StructurallyBuilder'. Я не хочу возвращать класс, владеющий 'StructurallyBuilder', я хочу вернуть сам' StructurallyBuilder' – Wins

+0

Nope. this.type указывает на построение структуры: – rssh