使用从类型枚举中选择的泛型 [英] Using a generic chosen from an enumeration of types

查看:56
本文介绍了使用从类型枚举中选择的泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在过去的24小时中,我一直在努力解决此问题,但收效甚微,并且已经发布了几个相关问题,如果有人以前见过,那么我深表歉意.我认为我想做的事情从概念上讲很简单,看起来像这样:

I've been grappling with this issue for the past 24 hours with little success, and already posted a couple of related questions, so apologies if anyone has seen it before. I think what I want to do is conceptually quite simple, and looks like this:

sealed trait DataType {
  type ElemT <: Numeric[ElemT] 
}
trait PositionsData extends DataType { type ElemT = Double }
trait WeightsData extends DataType { type ElemT = Double }

trait Error
case class TypeDoesntMatch() extends Error

case class DataPoint[T <: DataType] (
    point: T#ElemT
    ) { 
  def addToDataPoint(addTo: DataPoint[T]): Either[Error, DataPoint[T]] = 
    Right(DataPoint[T](this.point + addTo.point))
  // above method generates the error type mismatch; found: T#ElemT  required: String
  def addToDataPoint(addTo: DataPoint[_]): Either[Error, DataPoint[T]] = Left(TypeDoesntMatch()) 
}

// Example user behaviour - 
val d1 = DataPoint[PositionsData](1.1)
val d2 = DataPoint[PositionsData](2.2)
val d3 = DataPoint[WeightsData](3.3)

d1.addToDataPoint(d2) // should return Right(DataPoint[PositionsData](3.3))
d3.addToDataPoint(d2) // should return Left(TypeDoesntMatch())

这个想法是让图书馆的用户在创建(例如)DataPoint时从(数字)数据类型( DataType 特征)的预定义列表中进行选择.代码>.然后,该库的作者/维护者可以准确地设置每个 DataType 使用的数字数据类型,而无需用户查看.

The idea is to let the user of the library choose from a pre-defined list of (numeric) data types (the DataType trait) when creating (say) a DataPoint. The author/maintainer of the library can then set exactly what numeric data type each DataType uses, away from the user's view.

因此,我想定义一个 DataType 的枚举(一般意义上),每个枚举都有自己的关联数字类型.然后,我希望能够将它们作为泛型传递给DataPoint案例类.我遇到麻烦的地方是

So I'd like to define an enumeration (in the general sense) of DataTypes, each with their own associated numeric type. I'd then like to be able to pass these to the DataPoint case class as a generic. The bits I'm having trouble with are

a)我不知道如何仅将 ElemT 约束为 Numeric 类型-的< ;: Numeric [ElemT] 我认为下面的代码行不通,因为其他人指出, Double 不是 Numeric [Double] 的子类.

a) I can't figure out how to constrain ElemT to Numeric types only - the <: Numeric[ElemT] in the code below doesn't work, I think because, as others have pointed out, Double is not a subclass of Numeric[Double].

b)我很难弄清楚如何引入必要的隐式转换,以便在 this.point + addTo.point 中使用 Numeric.plus

b) I am having a bit of trouble figuring out how to introduce the necessary implicit conversion so that Numeric.plus is used in this.point + addTo.point.

我对如何实现这一目标一点都不挑剔,如果我的方法看起来完全错误,那么我很乐意被告知.衷心感谢能帮助我摆脱这种持续不断的打字难题的人.

I'm not at all fussy about how I achieve this and if my approach looks totally wrong then I'd be happy to be told that. Sincere thanks to anyone who can help me escape this on-going type-mare.

推荐答案

如果我理解这里的问题,一种解决方案可能是将 Numeric 要求移到与 DataType相同的位置要求(无论如何都需要添加).

If I understand the issues here, one solution might be to move the Numeric requirement to the same place as the DataType requirement (which is where the addition takes place anyway).

sealed trait DataType { type ElemT }
trait PositionsData extends DataType { type ElemT = Double }
trait WeightsData extends DataType { type ElemT = Double }

case class DataPoint[T <: DataType](point: T#ElemT
                                   )(implicit ev:Numeric[T#ElemT]) {
  import ev._
  def addToPoint(addTo: T#ElemT): DataPoint[T] =
    DataPoint[T](this.point + addTo)
}

这允许一些类型限制...

This allows some type restrictions...

//       DataPoint[WeightsData]("2.2") <- won't compile
val dp = DataPoint[WeightsData](2.2)
dp.addToPoint(4.1)
//res0: DataPoint[WeightsData] = DataPoint(6.3)

...但是它不会禁止数字扩展.(有人谈论将其从语言中删除,但是直到那时...)

...but it won't disallow numeric widening. (There's been some talk of removing this from the language, but, until then ...)

val dp = DataPoint[WeightsData](2) //Int
dp.addToPoint(48) //Int
//res0: DataPoint[WeightsData] = DataPoint(50.0) <- Double


更新对于更新的用户示例(有点希望您从此信息开始),我的建议仍然是:将 Numeric 类型限制移至 DataPoint 类.


UPDATE With the updated user examples (kinda wish you had started with that info) my suggestion remains: Move the Numeric type restriction to the DataPoint class.

. . . //as before
case class DataPoint[T <: DataType](point: T#ElemT
                                   )(implicit ev:Numeric[T#ElemT]) {
  import ev._
  def addToDataPoint(addTo: DataPoint[T]): DataPoint[T] =
    DataPoint[T](this.point + addTo.point)
}

// Example user behaviour -
val d1 = DataPoint[PositionsData](1.1)
val d2 = DataPoint[PositionsData](2.2)
val d3 = DataPoint[WeightsData](3.3)

d1.addToDataPoint(d2)
//d3.addToDataPoint(d2)  <- won't compile

通过 Either [_,_] 而不是编译时错误记录运行时错误没有任何优势.实际上,我认为这既会更难实现,也将失去作用.

I don't see any advantage in logging a runtime error, via Either[_,_], instead of a compile-time error. In fact, I think it would be both more difficult to achieve and less useful.

这篇关于使用从类型枚举中选择的泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆