如何“提取"类型参数以实例化另一个类 [英] How to "extract" type parameter to instantiate another class
问题描述
以下Scala代码有效:
The following Scala code works:
object ReducerTestMain extends App {
type MapOutput = KeyVal[String, Int]
def mapFun(s:String): MapOutput = KeyVal(s, 1)
val red = new ReducerComponent[String, Int]((a: Int, b: Int) => a + b)
val data = List[String]("a", "b", "c", "b", "c", "b")
data foreach {s => red(mapFun(s))}
println(red.mem)
// OUTPUT: Map(a -> 1, b -> 3, c -> 2)
}
class ReducerComponent[K, V](f: (V, V) => V) {
var mem = Map[K, V]()
def apply(kv: KeyVal[K, V]) = {
val KeyVal(k, v) = kv
mem += (k -> (if (mem contains k) f(mem(k), v) else v))
}
}
case class KeyVal[K, V](key: K, value:V)
我的问题是我想像这样实例化ReducerComponent
:
My problem is I would like to instantiate ReducerComponent
like this:
val red = new ReducerComponent[MapOutput, Int]((a: Int, b: Int) => a + b)
甚至更好:
val red = new ReducerComponent[MapOutput](_ + _)
这意味着很多事情:
- 我要类型检查
MapOutput
的类型为KeyVal[K, C]
, - 我要类型检查
C
是否与f
中使用的类型相同, - 我还需要提取"
K
以便实例化mem
,并从apply
进行类型检查参数.
- I would like to type-check that
MapOutput
is of the typeKeyVal[K, C]
, - I want to type-check that
C
is the same type used inf
, - I also need to "extract"
K
in order to instantiatemem
, and type-check parameters fromapply
.
有很多要问的吗? :)我想写一些类似的东西
Is it a lot to ask? :) I wanted to write something like
class ReducerComponent[KeyVal[K,V]](f: (V, V) => V) {...}
等到我将实例化ReducerComponent
的时候,我所拥有的全部是f
和MapOutput
,因此推断V是可以的.但是然后我只有KeyVal[K,V]
作为类的类型参数,它可能与KeyVal[_,_]
不同.
By the time I will instantiate ReducerComponent
all I have is f
and MapOutput
, so inferring V is OK. But then I only have KeyVal[K,V]
as a type parameter from a class, which can be different from KeyVal[_,_]
.
如果您了解类型推断的工作原理,我知道我要问的内容可能是疯狂的,但我没有!而且我什至不知道什么是继续进行的好方法-除了在我的高级代码中一直进行显式类型声明之外.我应该改变所有架构吗?
I know what I'm asking is probably crazy if you understand how type inference works, but I don't! And I don't even know what would be a good way to proceed --- apart from making explicit type declarations all the way up in my high-level code. Should I just change all the architecture?
推荐答案
只需编写一个简单的工厂:
Just write a simple factory:
case class RC[M <: KeyVal[_, _]](){
def apply[K,V](f: (V,V) => V)(implicit ev: KeyVal[K,V] =:= M) = new ReducerComponent[K,V](f)
}
def plus(x: Double, y: Double) = x + y
scala> RC[KeyVal[Int, Double]].apply(plus)
res12: ReducerComponent[Int,Double] = ReducerComponent@7229d116
scala> RC[KeyVal[Int, Double]]()(plus)
res16: ReducerComponent[Int,Double] = ReducerComponent@389f65fe
如您所见,ReducerComponent
具有适当的类型.这里使用隐式证据从M <: KeyVal[_, _]
中捕获K
和V
.
As you can see, ReducerComponent
has appropriate type. Implicit evidence is used here to catch K
and V
from your M <: KeyVal[_, _]
.
P.S.上面的版本要求为f
明确指定参数类型,例如(_: Double) + (_: Double)
.如果您想避免这种情况:
P.S. The version above requires to specify parameter types explicitly for your f
, like (_: Double) + (_: Double)
. If you want to avoid this:
case class RC[M <: KeyVal[_, _]](){
def factory[K,V](implicit ev: KeyVal[K,V] =:= M) = new {
def apply(f: (V,V) => V) = new ReducerComponent[K,V](f)
}
}
scala> RC[KeyVal[Int, Double]].factory.apply(_ + _)
res5: ReducerComponent[Int,Double] = ReducerComponent@3dc04400
scala> val f = RC[KeyVal[Int, Double]].factory
f: AnyRef{def apply(f: (Double, Double) => Double): ReducerComponent[Int,Double]} = RC$$anon$1@19388ff6
scala> f(_ + _)
res13: ReducerComponent[Int,Double] = ReducerComponent@24d8ae83
更新.如果要通用化keyval-使用类型函数:
Update. If you want to generelize keyval - use type function:
type KV[K,V] = KeyVal[K,V] //may be anything, may implement `type KV[K,V]` from some supertrait
case class RC[M <: KV[_, _]](){
def factory[K,V](implicit ev: KV[K,V] =:= M) = new {
def apply(f: (V,V) => V) = new ReducerComponent[K,V](f)
}
}
但是请记住,问题中的apply
仍然需要KeyVal[K,V]
.
But keep in mind that apply
from your question still takes KeyVal[K,V]
.
您还可以将KV
传递给某个类:
You can also pass KV
into some class:
class Builder[KV[_,_]] {
case class RC[M <: KV[_, _]](){
def factory[K,V](implicit ev: KV[K,V] =:= M) = new {
def apply(f: (V,V) => V) = new ReducerComponent[K,V](f)
}
}
}
scala> val b = new Builder[KeyVal]
scala> val f = b.RC[KeyVal[Int, Double]].factory
scala> f(_ + _)
res2: ReducerComponent[Int,Double] = ReducerComponent@54d9c993
这篇关于如何“提取"类型参数以实例化另一个类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!