2017-07-06 42 views
0

我遇到以下代碼(嚴重簡化)的問題。看起來問題可能與我使用抽象類型成員的方式有關。我希望有人指出並解釋我在這裏做錯了什麼。編譯器錯誤在底部。 我正在使用Scala版本2.12。如何在Scala中使用抽象類型成員

trait DataType { 
    type A 

    def convert(value: String): A 
    def convertToString(value: A): String 
} 

case object IntType extends DataType { 
    type A = Int 

    def convert(value: String): A = value.toInt 
    def convertToString(value: A): String = value.toString 
} 

trait Codec[T <: DataType] { 
    val dtype: T 

    def encode(data: Array[String]): Array[T#A] 
    def decode(data: Array[T#A]): Array[String] 
} 

class CodecImp[T <: DataType](val dtype: T)(implicit tag: ClassTag[T#A]) extends Codec[T] { 
    def encode(data: Array[String]): Array[T#A] = { 
     Array[T#A](dtype.convert(data(0))) 
    } 

    def decode(data: Array[T#A]): Array[String] = { 
     Array[String](dtype.convertToString(data(0))) 
    } 
} 

val cod = new CodecImp(IntType) 
val encoded = cod.encode(Array("1", "2", "3")) // expecting: Array[IntType.A] 
val decoded = cod.decode(encoded) // expecting: Array[String] 

編譯器錯誤。

Error:(30, 50) type mismatch; 
found : T#A 
required: CodecImp.this.dtype.A 
     Array[String](dtype.convertToString(data(0)))     
       ^

回答

0

的事情是,DataType每個實例都可以有A定義爲任何東西。試想一下:

class Foo extends DataType { 
    type A = Int 
    def convertToString(i: Int) = i.toString 
    def convert(s: String) = s.toInt 
} 

class Bar extends DataType { 
    type A = String 
    def convertToString(s: String) = s 
    def convert(s: String) = s 
} 

現在,如果我做val codecs = Seq(CodecImpl(new Foo, new Bar)

,如果可以編譯,那麼應該的說法是codecs.map(_.decode(whateverMakesSenseHere))什麼類型的?

這是行不通的......你不能這樣使用T#A,因爲它是抽象的。

我有一種感覺,你最好使用類型參數而不是路徑依賴類型來建模你需要的模型。對於後者來說,這看起來並不像是一個用例。 dtype#A,這種類型是由可變dtype決定,但data類型爲Array[T#A],所以這引起了類型不匹配,它不能解析:

1

這是由dtype.convertToString(data(0))這種方法想要一個變量型引起的在斯卡拉,由於我們不能說明我們的方法,如:def decode(data: Array[dType.A])...這是編譯器預計。

,您可以通過泛型類型 agains 類型別名解決這個問題,比如:

trait DataType[T] { 
    def convert(value: String): T 
    def convertToString(value: T): String 
} 

case object IntType extends DataType[Int] { 

    def convert(value: String): Int = value.toInt 
    def convertToString(value: Int): String = value.toString 
} 


class CodecImp[B](val dtype: DataType[B])(implicit tag: ClassTag[B]) { 
    def encode(data: Array[String]): Array[B] = { 
    Array[B](dtype.convert(data(0))) 
    } 

    def decode(data: Array[B]): Array[String] = { 
    Array[String](dtype.convertToString(data(0))) 
    } 
} 
+0

謝謝。我實際上在這裏使用過類型參數,但想要嘗試嵌套類型。 –

2

我發現What does the # operator mean in Scala?解釋了 '#' 運營得很好。
數據類型的每個實例都有它自己的路徑依賴型A.
之間的區別:T#A意義A是一個嵌套類的任何的T和dtype.A意味着A類的D型

你可以改變的編解碼器特徵的方法簽名到類似的東西:

def encode(data: Array[String]): Array[dtype.A] 
def decode(data: Array[dtype.A]): Array[String] 

但類型參數可能是一種更好的方式來表達關係。