Java Scala只接受列表中的字符串或Int泛型case类
我有一个case类,定义如下Java Scala只接受列表中的字符串或Int泛型case类,java,scala,Java,Scala,我有一个case类,定义如下 case class ChooseBoxData[T](index:T, text:String) 是否可以声明一个列表,使列表只接受ChooseBoxData[String]和ChooseBoxData[Int]的类型 我所期望的是: val specialList:List[some type declaration] = List( ChooseBoxData[String]("some string","some string"),/* allow,
case class ChooseBoxData[T](index:T, text:String)
是否可以声明一个列表,使列表只接受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): 并定义
chooseboxdata
,如下所示:
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))
这将保留索引
类型信息(当然是包装在StringInt
超类型中),稍后可以使用单个元素的模式匹配轻松提取这些信息
删除所有元素的包装器也很容易,但它会导致索引
类型变成Any
,这是我们所期望的,因为Any
是Scala类层次结构中String
和Int
的最低共同祖先
编辑:使用
因此,它允许编译,但会将无效实例替换为None
(如果需要,可以使用它抛出运行时错误),或者您可以使用以下方法直接筛选所需的实例:
list.flatMap(x => x.cast[ChooseBoxData[Int]])
//results in:
List[ChooseBoxData[Int]] = List(ChooseBoxData(1,txt))
您可以在case类之上构建额外的约束
import language.implicitConversions
case class ChooseBoxData[T](index:T, text:String)
trait MySpecialConstraint[T] {
def get: ChooseBoxData[T]
}
implicit def liftWithMySpecialConstraintString(cbd: ChooseBoxData[String]) =
new MySpecialConstraint[String] {
def get = cbd
}
implicit def liftWithMySpecialConstraintInt(cbd: ChooseBoxData[Int]) =
new MySpecialConstraint[Int] {
def get = cbd
}
// Now we can just use this constraint for out list
val l1: List[MySpecialConstraint[_]] = List(ChooseBoxData("A1", "B1"), ChooseBoxData(2, "B2"))
你为什么不能这样做:
object solution extends App {
case class ChooseBoxData[T](index: T, text: String) extends GenericType[T]
trait GenericType[T] {
def getType(index: T, text: String): ChooseBoxData[T] = ChooseBoxData[T](index, text)
}
val specialList = List(
ChooseBoxData[String]("some string", "some string"),
ChooseBoxData[Int](12, "some string"),
ChooseBoxData[Boolean](true, "some string")
)
println(specialList)
}
//output: List(ChooseBoxData(some string,some string), ChooseBoxData(12,some string), ChooseBoxData(true,some string))
可能是这样的:
trait AllowableBoxData
object AllowableBoxData {
private of[T](cbd: ChooseBoxData[T]) = new ChooseBoxData(cbd.index, cbd.text)
with AllowableBoxData
implicit def ofInt(cbd: ChooseBoxData[Int]) = of(cbd)
implicit def ofString(cbd: ChooseBoxData[String]) = of(cbd)
}
现在你可以做像这样的事情
val list: List[ChooseBoxData[_] with AllowableBoxData] = List(ChooseBoxData("foo", "bar"), ChooseBoxData(0, "baz")
但不是val list:list[AllowableBoxData]=list(选择boxdata(false,“baz”))
另外,如果您希望声明一个函数参数而不仅仅是一个变量,那么会有一个更优雅的解决方案:
trait CanUse[T]
implicit case object CanUseInt extends CanUse[Int]
implicit case object CanUseString extends CanUse[String]
def foo[T : CanUse](bar: List[ChooseBoxData[T]])
好。。。至少scala控制台在
val list=list(ChooseBoxData(“str”,“text”)、ChooseBoxData(1,“text”)、ChooseBoxData(true,“text”))方面没有问题。
@SarveshKumarSingh,对不起,我忘了添加如何定义case类。现在应该清楚了index
只能是StringInt
,它最终可以是字符串或Int。您好,感谢您的回答,第一个解决方案似乎不再允许我声明ChooseBoxData[Boolean],但我仍然需要它在其他类中,如果可能的话,我不希望使用过滤器,但目前看来,这似乎是最好的解决方案me@jialeko,使用无形状的解决方案返回布尔索引的None
。因此,如果运行时异常有效,可以使用它抛出运行时异常。对于使用ADT的解决方案,我想您可以在不同的类中扩展基本特征,以允许在不同的位置使用不同的规则。@jialeko,例如,如果您注释掉map
函数(case\u=>None
)中的最后一行,您将得到一个匹配错误。您能解释一下用户如何获得ChooseBoxData吗(Int,String)
或a从最终列表中选择BoxData(String,String)
?模式匹配可以帮助实现这一点。为此,我不希望更改案例类本身,因为它可能不受OP的控制。我尝试了l1(0).get.index
我得到了:res0:Any=A1
val ChooseBoxData(index:String,text)=l1(0)。get
我想值得注意的是,当要使用的类型是MySpecialConstraint
时,这种方法是有效的
编译并运行。您好,谢谢您的回答,但我对您的解决方案有点困惑……您能否进一步解释一下它如何不允许ChooseBoxData[Boolean]在列表中?实际上它也允许!布尔值。我将更新答案以满足您的要求。对象定义中的方法不应该有def
s吗?还有,如何从结果列表中提取ChooseBoxData
s?是的,错过了def
s,抱歉,不确定“如何提取…”是什么意思有几种方法,比如list.head
或者list.last
或者list(123)
等等……我不能list.head.index
或者list.head.text
though@jrook啊,是的……您需要将其声明为List[ChooseBoxData[\uux]with AllowableBoxData]
val list: List[ChooseBoxData[_] with AllowableBoxData] = List(ChooseBoxData("foo", "bar"), ChooseBoxData(0, "baz")
trait CanUse[T]
implicit case object CanUseInt extends CanUse[Int]
implicit case object CanUseString extends CanUse[String]
def foo[T : CanUse](bar: List[ChooseBoxData[T]])