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

类型类:在类型级别维护值

  •  3
  • jamborta  · 技术社区  · 8 年前

    我想创建一个 Int 存储的值如下:

    sealed trait Position {
      def value : Int
    }
    
    class P1 extends Position {val value = 1}
    class P2 extends Position {val value = 2} 
    

    当一个类扩展它时:

    case class PExtended() extends P1
    

    我想检索类型级别的值:

    def getValue[A <: Position] = ???
    getValue[PExtended] //should return 1
    

    我尝试了一些方法,但不确定这是否是解决这个问题的最佳方法。任何关于如何开始的建议都很好。

    2 回复  |  直到 8 年前
        1
  •  1
  •   Mikel San Vicente    8 年前

    您需要实现一个类型类,并使用无形状Nat数来解决这个问题:

    import shapeless.ops.nat.ToInt
    
    import shapeless.Nat
    import shapeless.ops.nat.ToInt
    
    trait Number[A] {
      def number: Int
    }
    
    object Number {
    
      def apply[A](implicit number: Number[A]): Number[A] = number
      implicit def positionNumber[A, N <: Nat](implicit eq: A <:< Position[N], toInt: ToInt[N]): Number[A] = {
        new Number[A] {
          override def number: Int = toInt.apply()
        }
      }
    }
    

    然后你可以用它来实现你的方法

    sealed trait Position[T <: Nat]
    
    class P1 extends Position[Nat._1]
    class P2 extends Position[Nat._2]
    
    object Test extends App {
      case class PExtended() extends P1
    
      def getValue[A](implicit number: Number[A]): Int = {
        number.number
      }
    
      println(getValue[PExtended])
    }
    
        2
  •  1
  •   Dmytro Mitin    8 年前

    您可以添加类型为的值 A

    def getValue[A <: Position](a: A): Int = a.value
    println(getValue(new PExtended))//1
    

    或制造 value a类型

    type One
    type Two
    
    sealed trait Position1 {
      type Value
    }
    
    class P11 extends Position1 { override type Value = One }
    class P21 extends Position1 { override type Value = Two }
    
    implicitly[P11#Value =:= P11#Value]//compiles
    implicitly[P11#Value =:= P21#Value]//doesn't compile
    

    或者可以使用隐式

    implicit val p1: P1 = new P1
    implicit val p2: P2 = new P2
    
    def getValue[A <: Position](implicit a: A): Int = a.value
    
    println(getValue[P1])//1
    println(getValue[P2])//2
    

    shapeless.Nat

    https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/nat.scala#L29-L49

    例如

    import shapeless.Nat
    import shapeless.ops.nat.{Sum, ToInt}
    import shapeless.Nat._
    
    implicitly[Sum.Aux[_2, _3, _5]]//compiles
    

    def calculateSum[N <: Nat, M <: Nat,
                     NplusM <: Nat](n: N, m: M)(implicit
      sum: Sum.Aux[N, M, NplusM],
      toInt: ToInt[NplusM]): Int = toInt()
    
    println(calculateSum(_2, _3)) // 5
    
    推荐文章