2016-12-09 2 views
3

Вот мой Scala код с некоторым примером использованием:Как сделать код более общим

object s { 
    import scala.reflect.runtime.universe._ 
    def apply[A <: In, B <: In](a: A, b: B) = foo(a, b) 
    def apply[A <: Int, B <: In](a: A, b: B)(implicit ev: TypeTag[B]) = foo(int(a), b) 
    def apply[A <: In, B <: Int](a: A, b: B)(implicit ev: TypeTag[A]) = foo(a, int(b)) 
    def apply(a: Int, b: Int) = foo(int(a), int(b)) 
    def apply(a: Int, b: Float) = foo(int(a), float(b)) 
    def apply(a: Int, b: Double) = foo(int(a), double(b)) 
    } 

    case class int(b: Int) extends In {} 
    case class float(b: Float) extends In {} 
    case class double(b: Double) extends In {} 

    case class foo[A <: In, B <: In](a: A, b: B) extends In {} 


    def usage = { 
     val a: struct[int, float] = s(int(1), float(3.1f)) 
     val b: struct[int, struct[int, int]] = s(int(1), s(in 
     val c: struct[int, int] =  s(3, int(5))    
     val d: struct[int, int] =  s(3, 7)     
     val e: struct[int, double] = s(6, 19.4)    
     val f: struct[struct[int, int], int] = s(s(1, 1), 9) 

     // all above work fine 
    } 

как я должен изменить код, чтобы принять любую комбинацию примитивных аргументов без ручного кодирования всех методов перегружать все случаи комбинаций?

Например, так что я могу иметь:

def wanted = { 
    s(34.4, 1.1) 
    s(1.3f, 1.1) 
    s(1.2, 123) 
} 

т.д.

ответ

1

Вы можете использовать Numeric типа для обработки всех числовых типов вместо них одну обработку одним:

trait In 

object s { 
    import scala.reflect.runtime.universe._ 
    def apply[A <: In, B <: In](a: A, b: B) = foo(a, b) 
    def apply[A <: AnyVal : Numeric, B <: In](a: A, b: B)(implicit ev: TypeTag[B]) = foo(numeric(a), b) 
    def apply[A <: In, B <: AnyVal : Numeric](a: A, b: B)(implicit ev: TypeTag[A]) = foo(a, numeric(b)) 
    def apply[A <: AnyVal : Numeric, B <: AnyVal : Numeric](a: A, b: B) = foo(numeric(a), numeric(b)) 
} 

case class numeric[B <: AnyVal : Numeric](b: B) extends In 

case class foo[A <: In, B <: In](a: A, b: B) extends In {} 


def usage = { 
    // these still work: 
    s(3, numeric(5)) 
    s(3, 7) 
    s(6, 19.4) 
    s(s(1, 1.1), 9.1) 

    // now these work too: 
    s(34.4, 1.1) 
    s(1.3f, 1.1) 
    s(1.2, 123) 

    // and this doesn't - as expected: 
    s(1, "bad!") 
} 
+0

Ну, почти. До: val c: struct [int, int] = s (3, int (5)) val x: struct [int, struct [int, int]] = s (3, s (3, int (5))) после вашего изменения: val c: struct [In with Product with Serializable, int] = s (3, int (5)) val x: struct [In with Product with Serializable, struct [In with Product with Serializable, int]] = s (3, s (3, int (5))) Теперь он разбивает другую часть моего API – Lambder

0

свой решение этой проблемы:

object s { 
    import scala.reflect.runtime.universe._ 

    trait Pi[T] { 
     type U <: In 
     def convert(x:T): U 
    } 
    implicit val fooInt = new Pi[Int] { type U = int; def convert(x:Int) = int(x) } 
    implicit val fooFloat = new Pi[Float] { type U = float; def convert(x:Float) = float(x) } 
    implicit val fooDouble = new Pi[Double] { type U = double; def convert(x:Double) = double(x) } 
    implicit def fooIn[T <: In] = new Pi[T] { type U = T; def convert(x:T) = x } 

    def apply[A, B](a: A, b: B)(implicit pi1: Pi[A], pi2: Pi[B]) = { 
     foo(pi1.convert(a), pi2.convert(b)) 
    } 

    } 

    case class int(b: Int) extends In {} 
    case class float(b: Float) extends In {} 
    case class double(b: Double) extends In {} 

    case class foo[A <: In, B <: In](a: A, b: B) extends In {} 


    def usage = { 
     val a: struct[int, float] = s(int(1), float(3.1f)) 
     val b: struct[int, struct[int, int]] = s(int(1), s(in 
     val c: struct[int, int] =  s(3, int(5))    
     val d: struct[int, int] =  s(3, 7)     
     val e: struct[int, double] = s(6, 19.4)    
     val f: struct[struct[int, int], int] = s(s(1, 1), 9) 

     // all above work fine 
    } 
Смежные вопросы