现在有几次我遇到了一个我认为应该可以通过路径依赖类型解决的问题,但我不确定我是否能够以最完整或最正确的方式这样做。在Java世界中,有一个枚举(或更常见的是以一堆静态值形式的伪枚举)定义一个映射到本机类型的闭合集并不罕见。 java.sql.Types
就是一个很好的例子:
public class Types {
/**
* <P>The constant in the Java programming language, sometimes referred
* to as a type code, that identifies the generic SQL type
* <code>BIT</code>.
*/
public final static int BIT = -7;
/**
* <P>The constant in the Java programming language, sometimes referred
* to as a type code, that identifies the generic SQL type
* <code>TINYINT</code>.
*/
public final static int TINYINT = -6;
/**
* <P>The constant in the Java programming language, sometimes referred
* to as a type code, that identifies the generic SQL type
* <code>SMALLINT</code>.
*/
public final static int SMALLINT = 5;
// ...
}
我想提供一些映射,它将把我从这些枚举带到它们的原生类型。到目前为止,我有这样的事情:
import java.sql.{Types, ResultSet}
trait SqlType {
def typeValue:Int
type Value
def getValue(rs:ResultSet, idx:Int):Value
}
object SqlType {
object SqlInt extends SqlType {
type Value = Int
def typeValue = Types.INTEGER
def getValue(rs:ResultSet, idx:Int) = rs.getInt(idx)
}
object SqlString extends SqlType {
type Value = String
def typeValue = Types.NVARCHAR
def getValue(rs:ResultSet, idx:Int) = rs.getString(idx)
}
def getSqlType(typeValue:Int):SqlType = typeValue match {
case Types.INTEGER => SqlInt
case Types.NVARCHAR => SqlString
}
implicit class ResultSetExtras(rs:ResultSet) {
def getCell(idx:Int, sqlType:SqlType):sqlType.Value = sqlType.getValue(rs, idx)
}
}
然而,这有点不稳定,因为我需要事先得到具体的SqlType
实例并将其作为函数的参数传递以获得正确的路径依赖类型。所以我似乎不能做这样的事情,这是我真正喜欢的事情:
implicit class ResultSetExtras2(rs:ResultSet) {
def getCell2(idx:Int):SqlType#Value = getSqlType(rs.getMetaData.getColumnType(idx)).getValue(rs, idx)
}
(注意SqlType#Value
的返回类型而不是路径依赖的sqlType.Value
。是否有(更好的)方法在纯scala中实现这一点?我怀疑像无形或宏这样的东西可能有帮助,但如果可能的话,我想知道路径依赖类型是否可行(或者宏确实优先于无形)。
答案 0 :(得分:1)
问题是rs.getCell(2)
无法在编译时知道将生成具体的具体类型的值。路径依赖类型在这里没有帮助。结果的类型只能在运行时知道。如果选择SqlType
的抽象类型作为返回值(就像java的情况那样),这不是问题。您无法获得SqlType#Value
所代表的实际类型。