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
,就有一些方法(您不必关心此方法是在对象上定义的,还是存在将对象转换为具有此方法的对象的隐式转换),然后可以使用视图边界。下面的示例要求type
t
具有method
def*(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)}
}