2015-12-03 1 views
2

У меня есть пример код, как это:Scala: как напечатать внутри класса с использованием типа параметризации

trait X{ 
    val a=1; 
    val b=2; 
} 

case class Y(override val a:Int, override val b:Int) extends X{ 
    def sum(c:Int)=a+b+c 
} 

case class Z(override val a:Int, override val b:Int) extends X{ 
    def sum(c:Int)=a+b+c+10 
} 



object Test{ 
    def main(args: Array[String]) { 
    val z = Z(1, 2) 
    val y = Y(3, 4) 
    println (y.sum(5)) 
    MyTest[Z].myprint(z) //error here 
    } 
} 

class MyTest[A] { 
    def myPrint(z: A): Unit = 
    if (z.isInstanceOf[A]) { 
     val c = z.asInstanceOf[A] 
     println(c.sum(4)) //error here 
    } 
} 

То, что я пытаюсь сделать, это создать параметризованный класс MyTest с функцией, которая будет печатать функцию sum класса, принятого как параметр. Я получаю две ошибки:

  1. не может разрешить символ MyTest
  2. Я не могу писать c.sum(), потому что очевидно, что компилятор не имеет никакой информации о том, какой класс может быть передан в А.

Обратите внимание, что если я положу метод myPrint внутри Test, который, во всяком случае, лучший дизайн, у меня все еще есть вторая проблема.

Что может быть для этого решением?

ответ

3

Вы не можете сделать

MyTest[Z].myprint(z) 

, как это класс, вы должны создать его экземпляр первого

val test = new MyTest[Z] 
test.myprint(z) 

Кстати уведомление, что вы объявили myPrint и использовать myprint, отличающийся идентификатор ...

или вы можете создать object с общим методом

object MyTest { 
    def myPrint[A](z: A): Unit = ??? 
} 

О другой проблеме, если вы хотите позвонить sum, сообщите компилятору, что myPrint принимает аргумент типа, который имеет этот метод.Например, вы можете поместить его в черту

trait X { 
    val a = 1 
    val b = 2 

    def sum(c: Int): Int 
} 

и реализовать его в подклассах

, то вы можете объявить его как

def myPrint(x: X): Unit = 
    println(x.sum(4)) 
} 

я поставил там 4 в качестве аргумента, как я понятия не имею, что вы действительно хотите усвоить, поскольку ваш код не передает никаких аргументов для функции, которую вы заявили, чтобы принять один Int

Другой способ от объявления типа (вместо добавления sum к вашему X черта заключается в создании еще одна черта

trait Summable { 
    def sum(c: Int): Int 
} 

и сделать ваши классы реализуют его

case class Y(override val a:Int, override val b:Int) extends X with Summable 

, а затем myPrint нужно будет принять Summable вместо X

, наконец, вы можете использовать структурную типизацию и объявить myPrint следующим образом:

def myPrint(x: { def sum(a: Int): Int }): Unit = 
    println(x.sum(4)) 
} 
+0

правый примерно аргумент вещь. редактирования. – rivu

+0

Я не прав о других вещах? Вам нужно больше объяснений или, может быть, я неправильно понял вашу проблему? –

+0

Нет, нет, вы правы. Я просто занимаю время, чтобы проверить вещи :) – rivu

1

Вы можете использовать Structural Types вместе с Bounds, что в основном определяет, какие методы или атрибуты должен иметь данный тип для использования с вашим классом. Это особенность, очень похожая на утиный тип динамических языков.

Таким образом, ваше определение класса можно переписать в следующем виде:

class MyTest[A <: { def sum(i: Int): Int }] 

Поскольку ваши sum методы получают аргумент призывание внутри myPrint должен передать его тоже. Исправлено, что рабочая версия вашего кода:

trait X { 
    val a = 1; 
    val b = 2; 
} 

case class Y(override val a: Int, override val b: Int) extends X { 
    def sum(c: Int) = a + b + c 
} 

case class Z(override val a: Int, override val b: Int) extends X { 
    def sum(c: Int) = a + b + c + 10 
} 

class MyTest[A <: { def sum(i: Int): Int }] { 
    def myPrint(z: A): Unit = 
    println(z.sum(0)) // I added a zero just to fix the example 
} 

object Test { 
    def main(args: Array[String]) { 
    val z = Z(1, 2) 
    val y = Y(3, 4) 
    println(y.sum(5)) 
    new MyTest[Z]().myPrint(z) //error here 
    } 
} 
Смежные вопросы