Conditional methods of Scala generic classes with restrictions for type parameters

前端 未结 3 567
花落未央
花落未央 2021-01-05 01:10

I believe that a generic class may make one of its methods available only assuming that its type parameters conform to some additional restrictions, something like (syntax i

相关标签:
3条回答
  • 2021-01-05 01:45

    You can also use a type bound on the type parameter, which is enforced by an implicit argument:

    trait Col[T] extends Traversable[T] {
        def sum(implicit ev: T <:< Int) :T = (0/:this)(_+_)
    }
    

    <:< is actually a class, expressed in infix notation, defined in Predef.scala and explained in many places, including here

    <:< means 'must be a subtype of'

    You can also use =:= 'must be equal to' and X <%< Y 'must be viewable as' (ie. there is an implicit conversion to X from Y)

    For a more detailed explanation of type constraints, see this SO question.

    0 讨论(0)
  • 2021-01-05 01:45

    there is another option involving implicit classes conversions

    trait Col[T] extends Traversable[T] 
    
    implicit class ColInt[T <: Int](val v : Col[T]) extends AnyVal {
        def sum : T = (0 /: v)(_ + _)
    }
    

    in this context you don't need the empty trait Col anymore, so you could further comprimize it to this:

    implicit class ColInt[T <: Int](val v : Traversable[T]) extends AnyVal {
        def sum : T = (0 /: v)(_ + _)
    }
    

    The advantage of this method is, that it tells the compiler, that type T is really a subtype of Int, so List[T] <: List[Int] is still valid in this context, and no explicit conversion needs to be added. The implicit parameter adds implicit conversions that wouldn't work on List[T], because it only introduces an implicit conversion from T to Int, not from List[T] to List[Int]

    0 讨论(0)
  • 2021-01-05 01:56

    In this case you can only use an implicit parameter, as the type gets determined before the method call.

    trait Col[T] extends Traversable[T] {
      def sum(implicit num: Numeric[T]) :T = ???
    }
    

    If the method you are calling would be parameterized, you could use context bounds, which are just syntactic sugar for the implicit parameter bound to the type parameter:

    def foo[A](implicit ev: Something[A]) = ???
    

    is equivalent to

    def foo[A : Something] = ???
    
    0 讨论(0)
提交回复
热议问题