Scala 如何确保某些类型具有特定的成员
我正在寻找一种方法,将我的多态类限制为具有特定成员函数的类型Scala 如何确保某些类型具有特定的成员,scala,Scala,我正在寻找一种方法,将我的多态类限制为具有特定成员函数的类型 class Table[T](bla: Array[T]) { val symbols = bla symbols.foreach( x => x * probability(x)) def probability(t: T) : Double = ... } 此代码未编译,因为没有成员*。我怎样才能保证这一点。我不想使用继承 编辑:实际实现了概率。它返回一个双精度 有什么想法吗?使用scala的结构类
class Table[T](bla: Array[T]) {
val symbols = bla
symbols.foreach( x => x * probability(x))
def probability(t: T) : Double = ...
}
此代码未编译,因为没有成员*。我怎样才能保证这一点。我不想使用继承
编辑:实际实现了概率。它返回一个双精度
有什么想法吗?使用scala的结构类型: 您的代码最终将显示如下所示:
class Table[T <: {def *(i:Int): T}](bla: Array[T]) {
...
}
class Table[T如果您不想使用继承,唯一可以应用的其他限制是上下文绑定。因此,如果您有一个可以使用的类列表,您可以创建一个隐式对象HasStar[X]
对于每个类X,使用一个上下文绑定,如T:HasStar
。我知道这可能不是您想要的,但我认为没有更好的选择。这个问题可以用不同的方法解决。例如,如果您只想键入T
,就有一些方法(您不必关心此方法是在对象上定义的,还是存在将对象转换为具有此方法的对象的隐式转换),然后可以使用视图边界。下面的示例要求typet
具有methoddef*(times:Int):t
:
class Table[T <% {def *(times: Int): T}](bla: Array[T]) {
bla.foreach( x => println(x * 2))
}
new Table(Array("Hello", "World"))
// Prints:
// HelloHello
// WorldWorld
列表
具有方法大小
,并且它也按预期工作
但如果您使用的是整数、浮点数、双精度等数值,这可能会更复杂。在这种情况下,我建议您使用上下文绑定。Scala有类型类。您可以使用它来处理数字,而不必知道它们的类型(使用Numeric
您实际上可以处理任何可以表示为数字的东西,因此您的代码将更加通用和抽象)。以下是一个示例:
import math.Numeric.Implicits._
class Table[T : Numeric](bla: Array[T]) {
bla.foreach( x => println(x * x))
}
new Table(Array(1, 2, 3))
// Prints:
// 1
// 4
// 9
new Table(Array(BigInt("13473264523654723574623"), BigInt("5786785634377457457465784685683746583454545454")))
// Prints:
// 181528856924372945350108280958825119049592129
// 33486887978237312740760811863500355048015109407078304275771413678604907671187978933752066116
更新
正如您在评论中指出的,Numeric
仍然不能解决您的问题,因为它只能处理相同类型的数字。您可以通过引入新的类型类来解决此问题。下面是一个示例:
import math.Numeric.Implicits._
trait Convert[From, To] {
def convert(f: From): To
}
object Convert {
implicit object DoubleToInt extends Convert[Double, Int] {
def convert(d: Double): Int = d.toInt
}
implicit object DoubleToBigInt extends Convert[Double, BigInt] {
def convert(d: Double): BigInt = d.toLong
}
}
type DoubleConvert[To] = Convert[Double, To]
class Table[T : Numeric : DoubleConvert](bla: Array[T]) {
bla.foreach( x => println(x * implicitly[DoubleConvert[T]].convert(probability(x))))
def probability(t: T) : Double = t.toDouble + 2.5
}
new Table(Array(1, 2, 3))
new Table(Array(BigInt("13473264523654723574623"), BigInt("5786785634377453434")))
使用DoubleConvert
类型类和T:Numeric:DoubleConvert
上下文绑定,您不仅说T
应该是某种数字,而且应该存在一些证据,证明它可以从Double
转换。您正在使用隐式[DoubleConvert]]
然后你用它将Double
转换为T
。我为Double->Int和Double->BigInt定义了convert
,但是你也可以为你需要的类型定义你自己的类型。其他人都用“结构类型”来回答。这是非常正确的,因为这是正确的答案
我不再重复显而易见的内容,而是将其展开。从Easy Angel的回复中摘录一段:
class Table[T <% {def *(times: Int): T}](bla: Array[T]) {
bla foreach {x => println(x*2)}
}
请修复您的代码好吗?缺少的成员是什么,它出现在代码中的什么位置,表中是否有概率方法,签名是什么?谢谢您的评论。缺少的成员是:*。这不起作用…scala>class Table[t new Table[Int](数组(1,2,4)):8:错误:类型参数[Int]不符合类表的类型参数界限[T我投了反对票,因为它不会做OP想要的事情,我也不知道如何让它做OP想要的事情。@Kim Stebel:真的。OP问题说编译器抱怨T没有成员函数。对于结构类型,你可以要求类型有一个特定的函数,而不用继承la duck类型。我的代码不值得编译,但那又怎样?谢谢你的努力,但这只适用于:x*x。它不适用于x*probability(x)其中probability返回一个Double。因此它似乎是*获取相同类型的参数。@peri4n:是的,你是对的。Numeric
只对相同类型的对象有效。但是为了进一步帮助你,我需要知道更多关于如何以及你试图存档什么的详细信息。如果能看到p的实现,那就太好了概率
。是否可以仅使用数值
中可用的方法来实现它?顺便说一句,您还可以更精确地使用积分
或分数
类型类。它们有更多的方法。还有其他解决方案(仍在使用数值
)对于这个问题,但是,我需要更多的信息。@peri4n:我用您描述的问题的简单解决方案更新了我的答案,但我仍然认为检查一下是否可以只使用数值来实现概率。
class Table[T <% {def *(times: Int): T}](bla: Array[T]) {
bla foreach {x => println(x*2)}
}
type HasTimes = {def *(times: Int): T}
class Table[T <% HasTimes](bla: Array[T]) {
bla foreach {x => println(x*2)}
}