java - Scala 只接受 List 中的 String 或 Int 通用案例类
问题描述
我有一个案例类定义如下
case class ChooseBoxData[T](index:T, text:String)
是否可以声明一个 List 以便该列表只接受 ChooseBoxData[String] 和 ChooseBoxData[Int] 的类型?
我的预期是这样的:
val specialList:List[some type declaration] = List(
ChooseBoxData[String]("some string","some string"),/* allow, because is ChooseBoxData[String]*/
ChooseBoxData[Int](12,"some string"), /* also allow, because is ChooseBoxData[Int]*/
ChooseBoxData[Boolean](true,"some string")/* not allow type other than ChooseBoxData[String] or ChooseBoxData[Int]*/
)
解决方案
这是我想出的:
首先,我们创建以下代数数据类型 (ADT):
sealed trait StringInt
case class Stringy(s : String) extends StringInt
case class Inty(s : Int) extends StringInt
并定义ChoooseBoxData
如下:
case class ChooseBoxData(index : StringInt, text : String)
然后我们定义以下隐含以将Int
和String
在范围内转换为定义的 ADT:
object CBImplicits {
implicit def conv(u : String) = Stringy(u)
implicit def conv2(u : Int) = Inty(u)
}
现在,我们可以强制执行问题中的要求。这是一个例子:
import CBImplicits._
val list = List(ChooseBoxData("str", "text"),
ChooseBoxData(1, "text"),
ChooseBoxData(true, "text"))
尝试运行上述代码,编译器会抱怨类型不匹配。但这将编译并运行:
List(
ChooseBoxData("str", "text"),
ChooseBoxData(1, "text"),
ChooseBoxData(12, "text2"))
这导致:
a: List[ChooseBoxData] =
List(ChooseBoxData(Stringy(str),text), ChooseBoxData(Inty(1),text), ChooseBoxData(Inty(12),text2))
这保留了index
类型信息(当然包装在StringInt
超类型中),以后可以使用单个元素的模式匹配轻松提取这些信息。
删除所有元素的包装器也很容易,但它会导致index
类型成为Any
我们所期望的,因为Any
它是两者String
以及Int
Scala 类层次结构中的最低共同祖先。
编辑:使用无形的解决方案
import shapeless._
import syntax.typeable._
case class ChooseBoxData[T](index : T, text : String)
val a = ChooseBoxData(1, "txt")
val b = ChooseBoxData("str", "txt")
val c = ChooseBoxData(true, "txt")
val list = List(a, b, c)
val `ChooseBoxData[Int]` = TypeCase[ChooseBoxData[Int]]
val `ChooseBoxData[String]` = TypeCase[ChooseBoxData[String]]
val res = list.map {
case `ChooseBoxData[Int]`(u) => u
case `ChooseBoxData[String]`(u) => u
case _ => None
}
//result
res: List[Product with Serializable] = List(ChooseBoxData(1,txt), ChooseBoxData(str,txt), None)
因此它允许编译,但会将无效实例替换为None
(如果需要,可以使用它来引发运行时错误),或者您可以直接过滤您想要使用的实例:
list.flatMap(x => x.cast[ChooseBoxData[Int]])
//results in:
List[ChooseBoxData[Int]] = List(ChooseBoxData(1,txt))
推荐阅读
- database - 在店外存储和查询异类事实|规则?
- css - 汉堡菜单中的滚动溢出
- python-3.x - Python,TypeError:没有编码的字符串参数
- javascript - 将事件侦听器添加到按钮时如何调试
- cmake - cmake add_custom_command 引入错误的依赖,除非 add_custom_target 也使用
- npm - Laravel - Bootstrap - NPM Watch 没有替换 css 匹配,它正在添加
- javascript - 当 Mac 设置(不是浏览器设置)拒绝位置共享时,HTML5 Geolocation API 悄然失败
- html - Html Css在两行和两列中删除两个div之间的距离
- javascript - 使用 react-transition-group 转换子路由时无法阻止父路由转换
- kotlin - 为什么使用 bylazy 会使我的 Kotlin 代码变慢