在Haskell中,我可以将参数约束到类型类,例如:
Prelude> f x y = x * y
Prelude> :t f
f :: Num a => a -> a -> a
我试图在Scala
中做同样的事情,如下所示:
def sendMessage[A: Array[Byte], B: Array[Byte]](producer: Eval[KafkaProducer[A, B]])(pr: Eval[ProducerRecord[A, B]]) =
但是编译器抱怨道:
[error] /home/developer/Desktop/scala/PureProducer/src/main/scala/TheProducer.scala:39:20: Array[Byte] does not take type parameters
[error] def sendMessage[A: Array[Byte], B: Array[Byte]](producer: Eval[KafkaProducer[A, B]])(pr: Eval[ProducerRecord[A, B]]) =
如何在Scala中约束类型参数?
答案 0 :(得分:5)
在Scala中,类类表示为通用特征,其实例作为隐式参数传递。作为示例,请使用以下Haskell类型类:
class Foo a where
foo :: a
bar :: a -> a -> a
f :: Foo a => a -> a
f x = bar foo x
instance Foo Int where
foo = 42
bar x y = x + y
f 23 -- Result: 42 + 23 = 65
Scala等价物看起来像这样:
// class Foo a
trait Foo[A] {
def foo: A
def bar(x: A, y: A): A
}
def f[A](x: A)(implicit foo: Foo[A]) = foo.bar(foo.foo, x)
// instance Foo Int
implicit case object FooInt extends Foo[Int] {
def foo = 42
def bar(x: Int, y: Int) = x + y
}
f(23) // Result: 42 + 23 = 65
还有一个定义隐式参数的快捷方式:def f[A: Foo](x: A)
是def f[A](x: A)(implicit _unnamed: Foo[A])
的缩写。但是,这意味着您无法直接在正文中访问类型类的实例(因为您没有给它起一个名字),所以只有当您所做的只是通过时,它才有用。键入类实例到其他方法(可以隐式完成,因此不需要名称)。
在Scala中,Num
类型类称为Numeric
,它提供plus
和times
等方法。因此,为了做与Haskell示例相同的事情,您可以写:
def f[A](x: A, y: A)(implicit num: Numeric[A]) = num.times(x,y)
Array[Byte]
尝试失败的原因是因为Array[Byte]
不是类型类。具体来说,A: Array[Byte]
缩写扩展到:
def sendMessage[A, B](producer: Eval[KafkaProducer[A, B]])(pr: Eval[ProducerRecord[A, B]])(implicit _unamed1: Array[Byte][A], implicit _unnamed2: Array[Byte][B])
看看应该清楚为什么这不起作用:Array[Byte][A]
没有任何意义。
根据您的评论,您只想避免多次写Array[Byte]
。这与类型类没有任何关系(在Haskell和Scala中都没有)。您可以简单地使用类型别名。
答案 1 :(得分:0)
如果你知道总是接受一个数组,只是约束内部类型,并且类型是相等的,所以你只需要一个类型变量,然后你想要成为子类型的类型,我不确定Byte是否可以被分类如此:
def sendMessage[A<:YourClass](producer: Eval[KafkaProducer[Array [A]])(pr: Eval[KafkaProducer[Array [A]]) =...
但我认为你可以做你的情况:
def sendMessage(producer: Eval[KafkaProducer[Array [Byte]])(pr: Eval[KafkaProducer[Array [Byte]]) =...