Scala 调用方法时确定参数类型时出现问题
我很抱歉这个模糊或可能不正确的问题,但我甚至不知道如何用一句话来陈述我的问题 我有两个特点:Scala 调用方法时确定参数类型时出现问题,scala,generics,Scala,Generics,我很抱歉这个模糊或可能不正确的问题,但我甚至不知道如何用一句话来陈述我的问题 我有两个特点: trait Property[T] { val name: String def conformsTo(rule: Rule[T]): Boolean } 及 我有一个实现Property的具体类列表和一个规则实现的映射,其中两个参数化类型可以是Double或字符串。 当遍历此列表时,对于每个属性实例,我将一个具体的规则实现传递给符合方法,但是编译器会出现类型不匹配的错误 因此,从更广泛的意
trait Property[T] {
val name: String
def conformsTo(rule: Rule[T]): Boolean
}
及
我有一个实现Property
的具体类列表和一个规则
实现的映射,其中两个参数化类型可以是Double
或字符串
。
当遍历此列表时,对于每个属性
实例,我将一个具体的规则
实现传递给符合
方法,但是编译器会出现类型不匹配的错误
因此,从更广泛的意义上讲,我试图获得的是一个属性列表,这些属性可以根据不同类型的给定规则集进行评估,而无需按类型将这些属性拆分为单独的列表
我尝试修补上/下限和隐式类型,但最终一无所获
完整代码:
trait Rule[T] {
def evaluate(valueToCheck: T): Boolean
}
case class GreaterThan(value: Double) extends Rule[Double] {
override def evaluate(valueToCheck: Double): Boolean = {
valueToCheck > this.value
}
}
case class LessThan(value: Double) extends Rule[Double] {
override def evaluate(valueToCheck: Double): Boolean = {
valueToCheck < this.value
}
}
case class Is(value: String) extends Rule[String] {
override def evaluate(valueToCheck: String): Boolean = {
valueToCheck == this.value
}
}
case class isNot(value: String) extends Rule[String] {
override def evaluate(valueToCheck: String): Boolean = {
valueToCheck != this.value
}
}
trait Property[T] {
val name: String
def conformsTo(rule: Rule[T]): Boolean
}
case class DoubleProperty(name: String, value: Double) extends Property[Double] {
override def conformsTo(rule: Rule[Double]): Boolean = rule.evaluate(value)
}
case class StringProperty(name: String, value: String) extends Property[String] {
override def conformsTo(rule: Rule[String]): Boolean = rule.evaluate(value)
}
object Evaluator extends App {
val ruleMap = Map(
"name1" -> GreaterThan(123),
"name1" -> LessThan(500),
"name2" -> GreaterThan(1000),
"name3" -> Is("something"))
val numericProperty = DoubleProperty("name1", 600)
val numericProperty2 = DoubleProperty("name2", 1000)
val stringProperty = StringProperty("name3", "something")
val stringProperty2 = StringProperty("name4", "something")
val attributes = List(
numericProperty,
numericProperty2,
stringProperty,
stringProperty2)
val nonConforming = attributes
.filter(x => ruleMap.contains(x.name))
.filter(x => !x.conformsTo(ruleMap(x.name))).toList
}
特质规则[T]{
def evaluate(valueToCheck:T):布尔值
}
案例类大于(值:Double)扩展了规则[Double]{
覆盖def求值(valueToCheck:Double):布尔={
valueToCheck>this.value
}
}
case类LessThan(值:Double)扩展了规则[Double]{
覆盖def求值(valueToCheck:Double):布尔={
valueToCheck大于(123),
“名称1”->小于(500),
“名称2”->大于(1000),
“name3”->是(“某物”))
val numericProperty=DoubleProperty(“名称1”,600)
val numericProperty2=双重属性(“名称2”,1000)
val stringProperty=stringProperty(“name3”,“某物”)
val stringProperty2=StringProperty(“名称4”,“某物”)
val属性=列表(
数字属性,
数字属性2,
stringProperty,
stringProperty2)
val=属性
.filter(x=>ruleMap.contains(x.name))
.filter(x=>!x.conformsTo(ruleMap(x.name))).toList
}
错误:
type mismatch;
found : Product with Rule[_ >: String with Double] with java.io.Serializable
required: Rule[(some other)<root>._1]
Note: Any >: _1 (and Product with Rule[_ >: String with Double] with java.io.Serializable <: Rule[_ >: String with Double]), but trait Rule is invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
.filter(x => !x.conformsTo(ruleMap(x.name))).toList
类型不匹配;
找到:具有规则[\u>:String with Double]且java.io.Serializable的产品
必需:规则[(某些其他)。\u 1]
注意:Any>:_1(以及java.io.Serializable:String with Double)中带有规则[>:String with Double]的产品),但trait规则在类型T中是不变的。
您可能希望将T定义为-T。(补充说明4.5)
.filter(x=>!x.conformsTo(ruleMap(x.name))).toList
感谢您的帮助。首先,根据错误消息,可以从可序列化的
产品中扩展规则
然后,错误消息更改为:
类型不匹配;
找到:App.Rule[_1(值$anonfun)],其中类型_1(值$anonfun)>:带双精度的字符串
必需:应用规则[._1]
其次,您可以使规则
逆变
trait Rule[-T] extends Product with Serializable {
def evaluate(valueToCheck: T): Boolean
}
类型不匹配;
找到:App.Rule[带双精度的字符串]
必需:应用规则[_1]
和属性
协变
trait Property[+T] {
val name: String
def conformsTo(rule: Rule[T]): Boolean
}
类型不匹配;
找到:App.Rule[带双精度的字符串]
必需:应用程序规则[任何]
问题是这不适用于列表
。attributes
的元素具有类型Property[Double]
和Property[String]
。但当您将它们添加到列表中时,它们丢失了各自的类型,变成了Property[Any]
(Property[Double | String]
,如果Scala 2中有联合类型)
类似地,ruleMap
的值具有类型Rule[Double]
和Rule[String]
。但是当你把它们和一些键放进地图时,它们丢失了各自的类型,变成了Rule[Double with String]
(甚至Rule[Nothing]
)
如果没有修改属性
和规则
的差异,则类型将是属性[\u]
和规则[\u]
(实际上,属性[\u1]
和规则[\u2]
),其中类型参数彼此不对应
但是conformsTo
的签名表示property.conformsTo(rule)
仅当参数具有相同T
的类型property[T]
和rule[T]
时才编译,这是无法保证的
您可以尝试使用而不是列表
和而不是映射
,以保留单个类型的元素。但是为了使过滤器
工作,您应该知道ruleMap.contains(x.name)
在编译时是否包含。因此,您必须使键具有单例类型和traitProperty
才能依赖于这一个类型参数trait Property[+T,S我相信简单的解决方案是为属性和规则的可能类型创建一个简单的ADT。@LuisMiguelMejíaSuárez如果我们执行筛选{case x:Property[T]=>x.conformsTo(ruleMap(x.name).asInstanceOf[Rule[t]]))
?我真的不太了解类型模式,我相信它是有效的,但在我看来它是不安全的。谢谢你的回答。@LuisMiguelMejíaSuárez-你能详细说明,你是指代数数据类型吗?@DmytroMitin是的,正如我所说,你的选择可能是安全的,而且显然更短。但老实说,我会做你所做的在那辆马车里
trait Property[+T] {
val name: String
def conformsTo(rule: Rule[T]): Boolean
}
val nonConforming = attributes
.filter(x => ruleMap.contains(x.name))
.filter{
case x: Property[t] => !x.conformsTo(ruleMap(x.name).asInstanceOf[Rule[t]])
}