Restrict specific type in Scala paramaters?

2019-09-10 10:32发布

问题:

Sometimes I come across a situation where I specifically want to restrict what can be sent to the function, but accept almost any other kind. Is this possible in Scala? For example, this code deals with my issue at runtime - accepting any type T except Option objects. Could the compiler catch it? Thank you

def apply[T:TypeTag](t: T): TaggedOption[T] =
  t match {
    case o: Option[_] =>
      // ensure this can't be created
      throw new Exception("This function doesn't work with Options")
    case other =>
      TaggedOption_(Some(t), PowerTag[T])
  }

回答1:

It is possible to restrict the type parameter:

scala> trait <:!<[A, B]
defined trait $less$colon$bang$less

scala> implicit def nsub[A, B] : A <:!< B = null
nsub: [A, B]=> <:!<[A,B]

scala> implicit def nsubAmbig1[A, B >: A] : A <:!< B = ???
nsubAmbig1: [A, B >: A]=> <:!<[A,B]

scala> implicit def nsubAmbig2[A, B >: A] : A <:!< B = ???
nsubAmbig2: [A, B >: A]=> <:!<[A,B]

scala> def notOption[A](a: A)(implicit ev: A <:!< Option[_]) = a
notOption: [A](a: A)(implicit ev: <:!<[A,Option[_]])A

scala> notOption(1)
res0: Int = 1

scala> notOption(List(""))
res1: List[String] = List("")

scala> notOption(Option(1))
<console>:14: error: ambiguous implicit values:
 both method nsubAmbig1 of type [A, B >: A]=> <:!<[A,B]
 and method nsubAmbig2 of type [A, B >: A]=> <:!<[A,B]
 match expected type <:!<[Option[Int],Option[_]]
              notOption(Option(1))
                       ^

scala> notOption(Some(1))
<console>:14: error: ambiguous implicit values:
 both method nsubAmbig1 of type [A, B >: A]=> <:!<[A,B]
 and method nsubAmbig2 of type [A, B >: A]=> <:!<[A,B]
 match expected type <:!<[Some[Int],Option[_]]
              notOption(Some(1))
                       ^

scala> notOption(None)
<console>:14: error: ambiguous implicit values:
 both method nsubAmbig1 of type [A, B >: A]=> <:!<[A,B]
 and method nsubAmbig2 of type [A, B >: A]=> <:!<[A,B]
 match expected type <:!<[None.type,Option[_]]
              notOption(None)
                       ^

The implicits make the Option case ambiguous. For a more detailed explanation on how the code is supposed to work, see the following thread on scala-user.



回答2:

Note: this is NOT a solution to your question, but a possible solution to your problem.

You could handle Option objects by unwrapping them first.

def apply[T:TypeTag](t: T): TaggedOption[T] =
  t match {
    case Some(x) =>
      apply(x)
    case None => TaggedNone // or whatever
    case other =>
      TaggedOption_(Some(t), PowerTag[T])
  }
}


标签: scala types