如何定义“类型析取"(联合类型)? [英] How to define "type disjunction" (union types)?
问题描述
一种具有 建议处理重载方法的双重定义是用模式匹配替换重载:
One way that has been suggested to deal with double definitions of overloaded methods is to replace overloading with pattern matching:
object Bar {
def foo(xs: Any*) = xs foreach {
case _:String => println("str")
case _:Int => println("int")
case _ => throw new UglyRuntimeException()
}
}
这种方法要求我们放弃对 foo
参数的静态类型检查.要是能写就好了
This approach requires that we surrender static type checking on the arguments to foo
. It would be much nicer to be able to write
object Bar {
def foo(xs: (String or Int)*) = xs foreach {
case _: String => println("str")
case _: Int => println("int")
}
}
我可以用 Either
来接近,但如果超过两种类型,它会很快变得丑陋:
I can get close with Either
, but it gets ugly fast with more than two types:
type or[L,R] = Either[L,R]
implicit def l2Or[L,R](l: L): L or R = Left(l)
implicit def r2Or[L,R](r: R): L or R = Right(r)
object Bar {
def foo(xs: (String or Int)*) = xs foreach {
case Left(l) => println("str")
case Right(r) => println("int")
}
}
看起来通用(优雅、高效)的解决方案需要定义 Either3
、Either4
、.... 有谁知道实现相同目标的替代解决方案结尾?据我所知,Scala 没有内置的类型分离".另外,上面定义的隐式转换是否潜伏在标准库中的某个地方,以便我可以导入它们?
It looks like a general (elegant, efficient) solution would require defining Either3
, Either4
, .... Does anyone know of an alternate solution to achieve the same end? To my knowledge, Scala does not have built-in "type disjunction". Also, are the implicit conversions defined above lurking in the standard library somewhere so that I can just import them?
推荐答案
好吧,在 Any*
的特定情况下,下面的这个技巧将不起作用,因为它不接受混合类型.但是,由于混合类型也不适用于重载,这可能就是您想要的.
Well, in the specific case of Any*
, this trick below won't work, as it will not accept mixed types. However, since mixed types wouldn't work with overloading either, this may be what you want.
首先,声明一个包含您希望接受的类型的类,如下所示:
First, declare a class with the types you wish to accept as below:
class StringOrInt[T]
object StringOrInt {
implicit object IntWitness extends StringOrInt[Int]
implicit object StringWitness extends StringOrInt[String]
}
接下来,像这样声明foo
:
object Bar {
def foo[T: StringOrInt](x: T) = x match {
case _: String => println("str")
case _: Int => println("int")
}
}
就是这样.您可以调用 foo(5)
或 foo("abc")
,它会起作用,但是尝试 foo(true)
它会失败.这可以由客户端代码通过创建 StringOrInt[Boolean]
来回避,除非,如 Randall 下面,你把 StringOrInt
变成一个 sealed
类.
And that's it. You can call foo(5)
or foo("abc")
, and it will work, but try foo(true)
and it will fail. This could be side-stepped by the client code by creating a StringOrInt[Boolean]
, unless, as noted by Randall below, you make StringOrInt
a sealed
class.
之所以有效,是因为 T: StringOrInt
意味着有一个 StringOrInt[T]
类型的隐式参数,并且因为 Scala 会查看某个类型的伴随对象内部是否存在隐含在那里使要求该类型的代码起作用.
It works because T: StringOrInt
means there's an implicit parameter of type StringOrInt[T]
, and because Scala looks inside companion objects of a type to see if there are implicits there to make code asking for that type work.
这篇关于如何定义“类型析取"(联合类型)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!