scala 泛型函数 return 类型
scala generic function return type
我尝试用通用 return 类型编写一个函数,但它不起作用,除非我强制转换 return 类型。请参阅下面的函数 getSomething()
我希望它可以在没有转换的情况下工作。我在这里做错了什么?
trait Sup
class Sub extends Sup {
def getString = "I am Sub"
}
class Sub2 extends Sup {
def getInt = 100
}
def getSomething[A <: Sup](str: String) : A = {
str match {
case "sub" => getSub.asInstanceOf[A]
case "sub2" => getSub2.asInstanceOf[A]
}
}
def getSub(): Sub = {
new Sub
}
def getSub2() : Sub2 = {
new Sub2
}
val x = getSomething[Sub]("sub").getString
val y = getSomething[Sub2]("sub2").getInt
不使用 asInstanceOf
时得到的错误消息会准确地告诉您哪里做错了。在 case "sub"
中,主体给出了一个 Sub
,编译器没有理由认为 A
是 Sub
的超类型(或者 Sub
可以隐式转换为 A
).
假设它有效。那么以下调用将是合法的:
val z = getSomething[Sub]("sub2").getString
或
trait Sub3 extends Sup
val w = getSomething[Sub3]("sup")
在这两种情况下应该发生什么?
正如 Alexey 所提到的,需要 instanceOf
才能在预期类型和对象类型 returned 之间强制 link。这相当于说:"Compiler, trust me, I'm giving you an 'A'" 这不是很安全,因为它取决于我们提供正确的类型。
如果我们想让类型系统为我们解决问题,我们需要给它一些额外的信息。在 Scala 中做到这一点的一种方法是定义一些工厂,它知道如何生成我们的类型的实例和允许该工厂 return 我们的特定类型的证据。
这是上面代码的一个版本,引入了这种构造并使用 ContextBounds
获取我们想要的类型的正确工厂实例。
trait Sup
class Sub extends Sup {
val str = "I'm a Sub"
}
class Sub2 extends Sup {
val number = 42
}
trait SupProvider[T <: Sup] {
def instance:T
}
object SupProvider {
def getSomeSup[T<:Sup:SupProvider]: T = implicitly[SupProvider[T]].instance
implicit object SubProvider extends SupProvider[Sub] {
def instance = new Sub
}
implicit object Sub2Provider extends SupProvider[Sub2] {
def instance = new Sub2
}
}
SupProvider.getSomeSup[Sub].str
// res: String = I'm a Sub
SupProvider.getSomeSup[Sub2].number
// res: Int = 42
我尝试用通用 return 类型编写一个函数,但它不起作用,除非我强制转换 return 类型。请参阅下面的函数 getSomething()
我希望它可以在没有转换的情况下工作。我在这里做错了什么?
trait Sup
class Sub extends Sup {
def getString = "I am Sub"
}
class Sub2 extends Sup {
def getInt = 100
}
def getSomething[A <: Sup](str: String) : A = {
str match {
case "sub" => getSub.asInstanceOf[A]
case "sub2" => getSub2.asInstanceOf[A]
}
}
def getSub(): Sub = {
new Sub
}
def getSub2() : Sub2 = {
new Sub2
}
val x = getSomething[Sub]("sub").getString
val y = getSomething[Sub2]("sub2").getInt
不使用 asInstanceOf
时得到的错误消息会准确地告诉您哪里做错了。在 case "sub"
中,主体给出了一个 Sub
,编译器没有理由认为 A
是 Sub
的超类型(或者 Sub
可以隐式转换为 A
).
假设它有效。那么以下调用将是合法的:
val z = getSomething[Sub]("sub2").getString
或
trait Sub3 extends Sup
val w = getSomething[Sub3]("sup")
在这两种情况下应该发生什么?
正如 Alexey 所提到的,需要 instanceOf
才能在预期类型和对象类型 returned 之间强制 link。这相当于说:"Compiler, trust me, I'm giving you an 'A'" 这不是很安全,因为它取决于我们提供正确的类型。
如果我们想让类型系统为我们解决问题,我们需要给它一些额外的信息。在 Scala 中做到这一点的一种方法是定义一些工厂,它知道如何生成我们的类型的实例和允许该工厂 return 我们的特定类型的证据。
这是上面代码的一个版本,引入了这种构造并使用 ContextBounds
获取我们想要的类型的正确工厂实例。
trait Sup
class Sub extends Sup {
val str = "I'm a Sub"
}
class Sub2 extends Sup {
val number = 42
}
trait SupProvider[T <: Sup] {
def instance:T
}
object SupProvider {
def getSomeSup[T<:Sup:SupProvider]: T = implicitly[SupProvider[T]].instance
implicit object SubProvider extends SupProvider[Sub] {
def instance = new Sub
}
implicit object Sub2Provider extends SupProvider[Sub2] {
def instance = new Sub2
}
}
SupProvider.getSomeSup[Sub].str
// res: String = I'm a Sub
SupProvider.getSomeSup[Sub2].number
// res: Int = 42