[英]F-bounded polymorphism - common supertype doesn't follow type bounds
我正在嘗試對具有強類型行數據訪問權限的表式集合進行建模。 我正在使用F界多態性(遞歸類型)模式,以便通過轉換來攜帶表類型信息(例如,通過表過濾的結果訪問DataView中的列列表)。 只要使用實際類型,一切都可以正常工作。 請查看下面的代碼片段,了解有問題的普通超型操作。
trait DataTable[A <: DataTable[A]] { self: A =>
def table: A = self
def name: String
}
class Table1 extends DataTable[Table1] {
val name = "Table1"
}
class Table2 extends DataTable[Table2] {
val name = "Table2"
}
def dump[A <: DataTable[A]](table: A) = println(table.name)
def getTable(name: String) = name match {
case "Table1" => new Table1
case "Table2" => new Table2
}
dump(new Table1())
dump(getTable("Table1") // doesn't typecheck...
最后一行產生編譯器錯誤:
inferred type arguments [DataTable[_2]] do not conform to method dump's type parameter bounds [A <: DataTable[A]]
found: DataTable[_2] where type _2 >: Table1 with Table2 <: DataTable[_ >: Table1 with Table2 <: Object]
似乎不能保留自身類型的邊界,而不能作為表1和表2的替代類型。 有任何已知的解決方法嗎?
更新:如果我錯了,請糾正我,但是我認為我錯誤地認為Table1和Table2具有共同的超類型,它具有DataTable的特征。 它們具有DataTable [_]的通用超類型,但這不再是有效的DataTable-而這正是Scala編譯器試圖告訴我的:)。
確實有可能嘗試使用存在性類型,但是將GenericDataTable類型引入為DataTable [A]的基礎將以更直接的方式解決問題。
以我為例-不幸的是,這並不容易-因為它需要建立互連類的另一個稱贊層次。
馬爾欽
我自己學會了一些想法,試圖弄清您的問題:
getTable的返回類型為:
def getTable(name: String): DataTable[_ >: Table1 with Table2 <: DataTable[_ >: Table1 with Table2]]
實際上是DataTable[_]
以下代碼也失敗:
val tbl: DataTable[_] = new Table1
dump(tbl)
這很有意義,因為dump期望使用DataTable
某些特定子類型,並且獲得其抽象類型DataTable[_]
。
因此,如果具體的子類型隱藏在其抽象超類型的后面,則我懷疑F邊界是否有意義:如果輸入類型為DataTable[_]
,那么如果您推斷出其后面的對象的特定子類型,我會感到驚訝靜態。
由於getTables
可以返回一種以上類型的DataTable
,因此其返回類型可能不能比DataTable[_]
更具體。 確實,這是最有前途的途徑,但是注釋中建議的解決方案尚未編譯:
def getTable(name: String): A forSome { type A <: DataTable[A] }
編輯:我做到了! 而且很奇怪!:
type DataTableSubtype = A forSome {type A <: DataTable[A]}
def convertToSubtype(tbl:DataTableSubtype): DataTableSubtype = tbl
def getTable(name: String): DataTableSubtype = {
name match {
case "Table1" => {convertToSubtype(new Table1)}
case "Table2" => {(new Table2())}
}
}
dump(getTable("Table1"))
訣竅是強制至少一個返回的表的類型A forSome {type A <: DataTable[A]
! 因此,具有各種子類型對象的工廠可以公開返回對象的具體類型! 我要說的很震驚。
我必須指出,轉儲可能只是:
def dump(table: DataTable[_]): Unit
當輸入類型也屬於返回類型時,我們首先要使用F綁定類型,例如:
def id[A <: DataTable[A]](table: A): A = table
由於這會靜態阻止我們獲取Table1並返回Table2。
總而言之, 當輸入的類型是 F綁定類型的具體子類型,並且該類型直接用於返回類型時 ,F綁定方法 (創建F綁定類型的動機)才有意義。作為A
或間接地作為Something[A]
。
那是catch-22的Scala版本。
您省略了返回類型,scala默默地計算了返回類型並給出了不相關的錯誤。
萬惡之源: 對於定義為DataTable[A <: DataTable[A]]
F邊界類型, DataTable[_]
不是正確的存在類型,它是DataTable[A] forSome {type A <: Any}
的簡寫DataTable[A] forSome {type A <: Any}
F綁定在這里丟失了。 正確的類型是DataTable[A] forSome { type A <: DataTable[A] }
Scala的不當行為:如果有疑問,類型檢查器會將類型推斷為DataTable[_]
類的東西。 嗯,它提高了精度,但是仍然失去了F約束 。
因此,答案是定義正確的類型並明確指定它:
object DataTable {
type Any = DataTable[A] forSome {type A <: DataTable[A]}
}
def getTable(name: String) : DataTable.Any = // fill here
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.