Scala 相等和有序[T]的继承(类层次结构)(类型参数擦除)
我希望有几个数据类,它们都有一个指定为 足以检查对象相等性。 但是这个Scala 相等和有序[T]的继承(类层次结构)(类型参数擦除),scala,pattern-matching,type-erasure,Scala,Pattern Matching,Type Erasure,我希望有几个数据类,它们都有一个指定为 足以检查对象相等性。 但是这个id:I不仅应该用于测试 平等的,但也是为了比较的目的。 这就是为什么视图绑定I为false } } /*应与所有其他真实的*/ val y12=新的YetAnotherIntId(12) val y13=新的YetAnotherIntId(13) y12 canEqual y13/*=>真*/ y12真*/ i12 canEqual y12/*=>正确*/ y12 canEqual i12/*=>假*/ i12==y12/*
id:I
不仅应该用于测试
平等的,但也是为了比较的目的。
这就是为什么视图绑定I为false
}
}
/*应与所有其他真实的*/
val y12=新的YetAnotherIntId(12)
val y13=新的YetAnotherIntId(13)
y12 canEqual y13/*=>真*/
y12真*/
i12 canEqual y12/*=>正确*/
y12 canEqual i12/*=>假*/
i12==y12/*=>false*/
y12==i12/*=>false*/
val j12=新长型(12L)
val j13=新长形(13L)
j12 canEqual j13/*=>正确*/
j12正确*/
i12 canEqual j12/*=>为true,但希望为false,因为Int!=长的*/
j12 canEqual i12/*=>正确“*/
i12==j12/*=>true“”*/
j12==i12/*=>true“”*/
val s12=新的字符串ID(“12”)
val s13=新的StringId(“13”)
s12 canEqual s13/*=>正确*/
s12真*/
i12 canEqual s12/*=>为true,但希望为false,因为Int!=串*/
s12 canEqual i12/*=>真“*/
i12==s12/*=>false*/
s12==i12/*=>false*/
谢谢你,如果你已经读了这么多,但是现在问题是:
我如何才能实现Ident[I].canEqual(Ident[J])
isfalse
forI!=J
不覆盖canEqual
像YetAnotherIntId
中那样
一个Ident[I]
似乎是一个Ident[J]
是一个Ident[]
,当使用this.id
和that.id
时,通过在Ident::canEqual
中注释掉,会产生问题(将true
替换为this.idthat.id | this.id==that.id
)
那么,为什么
Ident[Int].canEqual(Ident[Long])
是true
?是因为类型擦除吗?是否有可能用清单来“修复”这一点?或者是否有另一种可能性来确保I==J
?确实是类型擦除。您的案例中一定有一些警告:Ident[I]
。它检查您是否有一个标识[somehing]
,但不检查这个东西是否是I
(与java中相同)。
最好使用检查:Ident[\u]
中没有错误保证的地方
您的类中可能确实有一个清单
,并检查清单是否相等
class Ident[I <% Ordered](val id: I)(implicit val manifest: Manifest[I])
def canEqual(that: Any) = that match {
case Ident[_] if this.manifest == that.manifest => ...
case _ => false
}
}
class Ident[I。。。
大小写=>false
}
}
我建议I:Ordering
而不是I%Ordering
(一般来说,不仅仅是为了你的问题)。然后你可以比较订单,而不是清单。你也应该用它在ID上做相等的操作,这样你就知道它与订单是一致的
编辑您的评论
我认为这和拥有相同的排序
就足以说canEqual
是真的
。然后,你就有了这个.排序
,编译器知道它是一个排序[I]
和那。排序
这是编译器不知道的类型的排序。您必须使用第一个,这将意味着该.id对I的未检查强制转换(模式匹配或其他)。但是,检查排序相等性应足以确保强制转换是安全的(排序
是不变的)关于迪迪尔德的回答,他尝试使用一个隐式ord:Ordering[I]
替换其他必要的清单
,以确保类型兼容性
abstract class Ident[I](val id: I, dom: String = "")(implicit val ord: Ordering[I])
extends Equals with Ordered[Ident[I]]
{
protected val domain: AnyRef = if (dom != "") dom else ord
override lazy val hashCode = id.##
def canEqual(other: Any) = other match {
case that: Ident[_] => this.domain eq that.domain
case _ => false
}
override def equals(other: Any) = other match {
/* ugly: non variable type-argument I in type pattern Ident[I]
is unchecked since it is eliminated by erasure */
case that: Ident[I] if this.domain eq that.domain
=> (that canEqual this) && ord.compare(this.id, that.id) == 0
case _ => false
}
def compare(that: Ident[I]): Int = if (that canEqual this)
ord compare (this.id, that.id)
else
{
val message = "'%s' and '%s' are not comparable!" format (this, that)
throw new IllegalArgumentException(message)
}
lazy val nameId: String = getClass.getSimpleName + "#" + id
override def toString = nameId
}
可以创建域(子类层次结构),其元素彼此可比
默认情况下,/*在我的IDE中禁用了订单、子订单和所有其他详细的未检查(擦除)警告。您使用排序的建议听起来不错,因此尝试修改我的类类标识[I](val id:I)(隐式val-Order:Ordering[I])
。但是我如何实现equals
?我已经尝试了覆盖def equals(other:Any)=other match{case-that:Ident[X]if this.ord==that.ord=>(that canEqual this)和&ord.compare(this.id,that.id==0 case=>false}
我在为X使用I
时收到擦除警告,但是对于X,.id
当然不会编译。我可以在@未选中的情况下抑制警告吗?
/* should be comparable with all other <: Ident[Int] */
class IntId(i: Int) extends Ident[Int](i)
/* should be comparable only with itself */
class YetAnotherIntId(y: Int) extends Ident[Int](y) {
override def canEqual(other: Any) = other.isInstanceOf[YetAnotherIntId]
override def equals(other: Any) = other match {
case that: YetAnotherIntId => super.equals(that)
case _ => false
}
}
/* should be comparable with all other <: Ident[Long] */
class LongId(j: Long) extends Ident[Long](j)
/* should be comparable with all other <: Ident[String] */
class StringId(s: String) extends Ident[String](s)
val i12 = new IntId(12)
val i13 = new IntId(13)
i12 canEqual i13 /* => true */
i12 < i13 /* => true */
val y12 = new YetAnotherIntId(12)
val y13 = new YetAnotherIntId(13)
y12 canEqual y13 /* => true */
y12 < y13 /* => true */
i12 canEqual y12 /* => true */
y12 canEqual i12 /* => false */
i12 == y12 /* => false */
y12 == i12 /* => false */
val j12 = new LongId(12L)
val j13 = new LongId(13L)
j12 canEqual j13 /* => true */
j12 < j13 /* => true */
i12 canEqual j12 /* => true but want false because Int != Long */
j12 canEqual i12 /* => true '' */
i12 == j12 /* => true '' */
j12 == i12 /* => true '' */
val s12 = new StringId("12")
val s13 = new StringId("13")
s12 canEqual s13 /* => true */
s12 < s13 /* => true */
i12 canEqual s12 /* => true but want false because Int != String */
s12 canEqual i12 /* => true '' */
i12 == s12 /* => false */
s12 == i12 /* => false */
class Ident[I <% Ordered](val id: I)(implicit val manifest: Manifest[I])
def canEqual(that: Any) = that match {
case Ident[_] if this.manifest == that.manifest => ...
case _ => false
}
}
abstract class Ident[I](val id: I, dom: String = "")(implicit val ord: Ordering[I])
extends Equals with Ordered[Ident[I]]
{
protected val domain: AnyRef = if (dom != "") dom else ord
override lazy val hashCode = id.##
def canEqual(other: Any) = other match {
case that: Ident[_] => this.domain eq that.domain
case _ => false
}
override def equals(other: Any) = other match {
/* ugly: non variable type-argument I in type pattern Ident[I]
is unchecked since it is eliminated by erasure */
case that: Ident[I] if this.domain eq that.domain
=> (that canEqual this) && ord.compare(this.id, that.id) == 0
case _ => false
}
def compare(that: Ident[I]): Int = if (that canEqual this)
ord compare (this.id, that.id)
else
{
val message = "'%s' and '%s' are not comparable!" format (this, that)
throw new IllegalArgumentException(message)
}
lazy val nameId: String = getClass.getSimpleName + "#" + id
override def toString = nameId
}
/* Order, SubOrder and all other <: Ident[Int] without explicit dom are comparable */
class Order(i: Int) extends Ident[Int](i)
class SubOrder(i: Int) extends Order(i)
/* Node and SubNode's are in its own "Node" named domain
and comparable only among each other */
class Node(i: Int) extends Ident[Int](i, "Node")
class SubNode(i: Int) extends Node(i)