使用相同类型的参数作为参数类型和带有匹配表达式的参数类型
Using same type parameter as argument type and parameter type with match expression
我在编译以下示例代码时遇到错误。
abstract class Base
case class A(i: Int) extends Base
case class B(s: String) extends Base
class Transform {
def func[T <: Base](arg: T): T = arg match {
case A(i) => A(i)
case B(s) => B(s)
}
}
错误是
Example.scala:9: error: type mismatch;
found : A
required: T
case A(i) => A(i)
^
Example.scala:10: error: type mismatch;
found : B
required: T
case B(s) => B(s)
^
two errors found
这些错误是合理的。
为了避免这种情况,我需要将 asInstanceOf[T]
放在 A(i).asInstanceOf[T]
这样的实例化后面。但是,如果有很多匹配案例模式,那么对所有 return 值都这样做很烦人。
此外,我想使用 Transform
class 作为父级 class 并覆盖 func()
以执行如下代码的特定操作。
class ExtTransform extends Transform {
override def func[T <: Base](arg: T): T = arg match {
case A(i) => A(i + 1)
case _ => super.func(arg)
}
}
是否有更好的方法或技巧?
我建议改用 typeclass。
sealed trait Base
object Base {
final case class A() extends Base
final case class B() extends Base
sealed trait Builder[T <: Base] {
def build(): T
}
object Builder {
final implicit val ABuilder: Builder[A] = new Builder[A] {
override def build(): A = A()
}
final implicit val BBuilder: Builder[B] = new Builder[B] {
override def build(): B = B()
}
}
}
object Main extends App {
def func[T <: Base](implicit builder: Base.Builder[T]): T =
builder.build()
func[Base.A] // res: Base.A = A()
func[Base.B] // res: Base.B = B()
}
To avoid this, I need to put asInstanceOf[T] behind instantiation like A(i).asInstanceOf[T]. However, it is annoying to do like that for all return value if there are a lot of match case patterns.
嗯,这个问题很简单:把它放在比赛结束时的一个地方,而不是每个分支。
override def func[T <: Base](arg: T): T = (arg match {
case A(i) => A(i)
case B(s) => B(s)
}).asInstanceOf[T]
但请注意,您的设计本质上是不安全的,因为除了 Base
、A
和 B
之外还有 Base
的子类型:单例类型(a.type
), 复合类型 (A with SomeTrait
), Null
... 并且它们中的任何一个都可以用作 T
。重载可能更好:
class Transform {
def func(arg: Base): Base = arg match {
case arg: A => func(arg)
case arg: B => func(arg)
}
def func(arg: A): A = arg
def func(arg: B): B = arg
}
class ExtTransform extends Transform {
override def func(arg: A): A = A(arg.i + 1)
}
我在编译以下示例代码时遇到错误。
abstract class Base
case class A(i: Int) extends Base
case class B(s: String) extends Base
class Transform {
def func[T <: Base](arg: T): T = arg match {
case A(i) => A(i)
case B(s) => B(s)
}
}
错误是
Example.scala:9: error: type mismatch;
found : A
required: T
case A(i) => A(i)
^
Example.scala:10: error: type mismatch;
found : B
required: T
case B(s) => B(s)
^
two errors found
这些错误是合理的。
为了避免这种情况,我需要将 asInstanceOf[T]
放在 A(i).asInstanceOf[T]
这样的实例化后面。但是,如果有很多匹配案例模式,那么对所有 return 值都这样做很烦人。
此外,我想使用 Transform
class 作为父级 class 并覆盖 func()
以执行如下代码的特定操作。
class ExtTransform extends Transform {
override def func[T <: Base](arg: T): T = arg match {
case A(i) => A(i + 1)
case _ => super.func(arg)
}
}
是否有更好的方法或技巧?
我建议改用 typeclass。
sealed trait Base
object Base {
final case class A() extends Base
final case class B() extends Base
sealed trait Builder[T <: Base] {
def build(): T
}
object Builder {
final implicit val ABuilder: Builder[A] = new Builder[A] {
override def build(): A = A()
}
final implicit val BBuilder: Builder[B] = new Builder[B] {
override def build(): B = B()
}
}
}
object Main extends App {
def func[T <: Base](implicit builder: Base.Builder[T]): T =
builder.build()
func[Base.A] // res: Base.A = A()
func[Base.B] // res: Base.B = B()
}
To avoid this, I need to put asInstanceOf[T] behind instantiation like A(i).asInstanceOf[T]. However, it is annoying to do like that for all return value if there are a lot of match case patterns.
嗯,这个问题很简单:把它放在比赛结束时的一个地方,而不是每个分支。
override def func[T <: Base](arg: T): T = (arg match {
case A(i) => A(i)
case B(s) => B(s)
}).asInstanceOf[T]
但请注意,您的设计本质上是不安全的,因为除了 Base
、A
和 B
之外还有 Base
的子类型:单例类型(a.type
), 复合类型 (A with SomeTrait
), Null
... 并且它们中的任何一个都可以用作 T
。重载可能更好:
class Transform {
def func(arg: Base): Base = arg match {
case arg: A => func(arg)
case arg: B => func(arg)
}
def func(arg: A): A = arg
def func(arg: B): B = arg
}
class ExtTransform extends Transform {
override def func(arg: A): A = A(arg.i + 1)
}