简体   繁体   English

Scala-组成通用类型

[英]Scala - composing generic types

I want to create a generic interface which hides the implementation of the hash function on the key of a product (which is used to lookup products and for various caching and calculations outside the scope of the product itself). 我想创建一个通用接口,该接口在产品键上隐藏hash函数的实现(用于查找产品以及产品本身范围之外的各种缓存和计算)。 I want to tie the concrete implementation of the hash function to the particular reader which implements the interface. 我想将散列函数的具体实现与实现该接口的特定阅读器联系起来。 I am doing this for various consistency reasons and since the products are stored in a cache and might be migrated in the future and I want to assure that the lookup is always using the same hash . 我出于各种一致性原因进行此操作,并且由于产品存储在缓存中,并且将来可能会迁移,因此我想确保查找始终使用相同的hash I have some syntax issues on how to compose generics in this fashion . 关于如何以这种方式编写泛型,我有一些语法问题。

For example this type of hierarchy I am having syntax issues: 例如,这种类型的层次结构存在语法问题:

trait Hash {
  type U
  type V
  def hash(u:U) : V
}

trait Product[hasher <: Hash] { 
   val key : hasher#U
   // hasher.hash(x : U) => V
   def hashKey : hasher#V
}

trait ProductReader[product <: Product] { // error: type 'Product' takes parameters - but I don't want to define them at this point yet...
   def getByKey(key : U) : Product
   def getByHashed(hash : V) : Product
}

Example usage is: 用法示例是:

object MyHash extends Hash[String,Long] {
  def hash(key : String) : Long = mySpecialHash(key)
}

// implements serialization (together with the hasher)
class MyProduct[MyHash[String,Long]](val key : String {
  def hashKey : Long = MyHash.hash(key)
}

class MyProductReader[MyProducts[MyHash[String,Long]] {
   def getByKey(key : String) : MyProduct[MyHash[String,Long]] = ....
   def getByHashed(hash : Long) : MyProduct[MyHash[String,Long]] = ...
}

You can use abstract type members instead of generic type parameters if you don't want to bind a specific Product at that point of declaration: 如果不想在声明时绑定特定Product ,则可以使用抽象类型成员而不是通用类型参数:

trait Hash {
  type U
  type V
  def hash(u: U): V
}

trait Product {
  type Hasher <: Hash

  val key: Hasher#U
  def hashKey: Hasher#V
}

trait ProductReader[P <: Product] {
  def getByKey(key: P#Hasher#U): P
  def getByHashed(hash: P#Hasher#V): P
}

object MyHash extends Hash {
  override type U = String
  override type V = Long

  def hash(key: String): Long = ???
}

class MyProduct(val hasher: MyHash.type) extends Product {
  override type Hasher = hasher.type

  def hashKey: Long = MyHash.hash(key)
  override val key: String = "MyProduct"
}

class MyProductReader extends ProductReader[MyProduct] {
  override def getByKey(key: String): MyProduct = ???
  override def getByHashed(hash: Long): MyProduct = ???
}

An additional approach would be adding an additional type parameter. 另一种方法是添加其他类型参数。 It really depends on your flavor, and I think using a type member in this case ends up being less verbose. 这实际上取决于您的口味,我认为在这种情况下使用类型成员最终会变得不太冗长。

You can add a second parameter type to ProductReader 您可以向ProductReader添加第二个参数类型

trait Hash {
  type U
  type V
  def hash(u:U) : V
}

trait Product[hasher <: Hash] { 
   val key : hasher#U
   // hasher.hash(x : U) => V
   def hashKey : hasher#V
}

trait ProductReader[hasher <: Hash, product <: Product[hasher]] { 
   def getByKey(key : hasher#U) : product
   def getByHashed(hash : hasher#V) : product
}

Now, with your sample usage : 现在,使用您的示例用法:

object MyHash extends Hash {
  type U = String
  type V = Long
  def hash(key : String) : Long = key.toLong
}

class MyProduct(val hasher: MyHash.type) extends Product[MyHash.type] {
  def hashKey: Long = hasher.hash(key)

  val key: String = "MyProduct"
}

class MyProductReader extends ProductReader[MyHash.type, MyProduct] {
   def getByKey(key : String) : MyProduct = ???
   def getByHashed(hash : Long) : MyProduct = ???
}

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

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