简体   繁体   English

Scala Generics - ADT中的通用提取器方法

[英]Scala Generics - generic extractor method in an ADT

I have an ADT like; 我喜欢ADT;

sealed trait Dimension
case object Customer extends Dimension
case object Brand extends Dimension
case object Product extends Dimension

Now this ADT represents values in a data class 现在,此ADT表示数据类中的值

case class Record(custId: Long, prodId: Int, brand: String)

How could I write an 'dimension extractor' such that if I pass in any Dimension type and an instance of Record I get the value it represents? 我怎么能写一个'尺寸提取器',这样如果我传入任何Dimension类型和Record的实例我得到它代表的值?

In other words I have a Seq[Dimension](Brand,Customer).foreach{d => println(d.extract(aRecord))} 换句话说,我有一个Seq[Dimension](Brand,Customer).foreach{d => println(d.extract(aRecord))}

First thought was to do something like; 首先想到的是做一些事情;

trait DimExtractor[A,B] {
  val extract = A => B
}

then change the ADT: 然后改变ADT:

case object Brand extends Dimension with DimExtractor[Record, String] {
  val extract = (r: Record) => r.brand
}

Is there a way to implicitly pick up the type String based on the return type of r.brand? 有没有办法隐式地根据r.brand的返回类型获取String类型? Maybe making this a def? 也许这是一个def?

But this doesn't work because a Seq[Dimension with DimExtractor] wont compile because it needs type params... But I have lots of DimExtractor[Record, ?] (ie one for Brand which returns a String, on for Customer which returns a long etc... 但这不起作用,因为Seq[Dimension with DimExtractor]不会编译,因为它需要类型参数...但我有很多DimExtractor[Record, ?] (即一个用于Brand,它返回一个String,on为Customer返回很久......

I could make it a DimExtractor[Record, Any]... but again this doesnt seem right. 我可以把它变成DimExtractor [Record,Any] ......但是这看起来并不合适。

Whats a better way to do this? 什么是更好的方法来做到这一点?

You have 3 subclass (object) of the Dimension trait and the extractor's return value depends on the argument type (consider both a and b as arguments of method in a.method(b) ). 你有2个Dimension特征的子类(对象),而提取器的返回值取决于参数类型(同时考虑ab作为a.method(b)method参数)。 You can use a path-dependent type. 您可以使用路径依赖类型。

sealed trait Dimension {
}

trait DimExtractor[R] {
  type Ret
  def extract(r: R): Ret
}

case object Customer extends Dimension with DimExtractor[Record] {
  type Ret = Long
  def extract(r: Record): Ret = r.custId
}
case object Brand extends Dimension with DimExtractor[Record] {
  type Ret = String
  def extract(r: Record): Ret = r.brand
}
case object Product extends Dimension with DimExtractor[Record] {
  type Ret = Int
  def extract(r: Record): Ret = r.prodId
}

case class Record(custId: Long, prodId: Int, brand: String)

Now you can write your example as 现在你可以把你的例子写成

val aRecord = Record(1, 1, "asd")
Seq[DimExtractor[Record]](Brand, Customer).foreach { d => println(d.extract(aRecord)) }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM