如何“提取"类型参数以实例化另一个类 [英] How to "extract" type parameter to instantiate another class

查看:102
本文介绍了如何“提取"类型参数以实例化另一个类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下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](_ + _)

这意味着很多事情:

  1. 我要类型检查MapOutput的类型为KeyVal[K, C]
  2. 我要类型检查C是否与f中使用的类型相同,
  3. 我还需要提取" K以便实例化mem,并从apply进行类型检查参数.
  1. I would like to type-check that MapOutput is of the type KeyVal[K, C],
  2. I want to type-check that C is the same type used in f,
  3. I also need to "extract" K in order to instantiate mem, and type-check parameters from apply.

有很多要问的吗? :)我想写一些类似的东西

Is it a lot to ask? :) I wanted to write something like

class ReducerComponent[KeyVal[K,V]](f: (V, V) => V) {...}

等到我将实例化ReducerComponent的时候,我所拥有的全部是fMapOutput,因此推断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[_, _]中捕获KV.

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屋!

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