代码之家  ›  专栏  ›  技术社区  ›  yiksanchan

从类型参数获取子类型参数

  •  0
  • yiksanchan  · 技术社区  · 6 年前

    让我们建立一些背景。 Data Metadata Payload .

    trait Data[Metadata <: Product, Payload <: Product] extends Product {
      def metadata: Metadata
      def payload: Payload
    }
    
    case class M()
    case class P()
    case class D(metadata: M, payload: P) extends Data[M, P]
    

    Processor 处理 元数据 不一样。

    trait MetadataProcessor[Metadata <: Product] {
      def apply() = "process metadata"
    }
    trait PayloadProcessor[Payload <: Product] {
      def apply() = "process payload"
    }
    
    // both work
    new MetadataProcessor[M]{}.apply() // "process metadata"
    new PayloadProcessor[P]{}.apply() // "process payload"
    

    希望如此 DataProcessor 元数据 有效载荷 . 这是一种方法:

    trait DataProcessor[Metadata <: Product, Payload <: Product] {
      def apply() = {
            new MetadataProcessor[Metadata]{}.apply() +
            new PayloadProcessor[Payload]{}.apply()   
      }
    }
    new DataProcessor[M,P]{}.apply() // "process metadataprocess payload"
    

    new DataProcessor[D]{}.apply() 得到完全相同的输出。怎么做?

    对于具有上述代码的交互式Scala环境,请随意查看 Scastie playground .

    1 回复  |  直到 6 年前
        1
  •  1
  •   Dmytro Mitin    6 年前

    试着使 Metadata Payload type members rather than type parameters 并使用类型投影 Data#Metadata , Data#Payload .

    trait Data extends Product {
      type Metadata <: Product
      type Payload <: Product
      def metadata: Metadata
      def payload: Payload
    }
    
      // This is optional, just in case if you need also type parameters Metadata and Payload.
      // Then you can use them as Data.Aux[Metadata, Payload]
    //  object Data {
    //    type Aux[Metadata0 <: Product, Payload0 <: Product] = Data { type Metadata = Metadata0; type Payload = Payload0 }
    //  }
    
    case class M()
    case class P()
    case class D(metadata: M, payload: P) extends Data { type Metadata = M; type Payload = P }
    
    trait MetadataProcessor[Metadata <: Product] {
      def apply() = "process metadata"
    }
    trait PayloadProcessor[Payload <: Product] {
      def apply() = "process payload"
    }
    
    new MetadataProcessor[M]{}.apply() // "process metadata"
    new PayloadProcessor[P]{}.apply() // "process payload"
    
    trait DataProcessor[A <: Data] {
      def apply() = {
        new MetadataProcessor[A#Metadata]{}.apply() +
          new PayloadProcessor[A#Payload]{}.apply()
      }
    }
    
    new DataProcessor[D]{}.apply() // "process metadataprocess payload"