Scala 多态回调类型不匹配
Scala polymorphic callback type mismatch
对不起,我找不到更好的标题。
我正在努力实现如下目标
abstract class Person
case class User(uid: String, firstname: String, active: String) extends Person
case class Admin(id: String, pseudo: String, securityClearance: String) extends Person
def innerFunctionForUser(user: User): List[String] = {
List() :+ user.uid :+ user.firstname :+ user.active
}
def innerFunctionForAdmin(admin: Admin): List[String] = {
List() :+ admin.id :+ admin.psuedo :+ admin.securityClearance
}
def outerFunction(person: Person, innerFunction: (Person) => List[String]): List[String] = {
innerFunction(person)
}
所以我可以像那样使用它
val myUser = User("0c60c5b4-306d-4372-b60d-fd699c80e408", "joe", "false")
val myAdmin = Admin("178789", "jack", "high")
outerFunction(myUser, innerFunctionForUser)
outerFunction(myAdmin, innerFunctionForAdmin)
没有类型检查
type mismatch;
found : User => List[String]
required: Person => List[String]
而且我不能让 innerFunction 接受这样的人
def innerFunctionForUser(user: Person): List[String] = {
List() :+ user.uid :+ user.firstname :+ user.active
}
我在这里保持简单,但我需要 case class 具有不同类型的参数和不同数量的参数。
所以我不能在摘要 class Person 中声明它们。
这会给
value uid is not a member of Person
value firstname is not a member of Person
value active is not a member of Playground.Person
如何使类型和数字参数不同的不同案例 class 的计算结果相同?
AND/OR
如何使回调多态,像这样
def outerFunction(person: Person, innerFunction: (SomeCaseClass) => List[String]): List[String] = {
innerFunction(person)
}
希望这已经够清楚了。
感谢阅读,祝您玩得愉快。
User
和 Admin
是 Person
的子类型,但 User => List[String]
和 Admin => List[String]
不是 的子类型 Person => List[String]
。 User => List[String]
和 Admin => List[String]
实际上是 Person => List[String]
的 超类型 。函数类型 A => B
相对于 B
是 covariant 但相对于 A
.
是逆变的
努力做到outerFunction
generic
def outerFunction[P <: Person](person: P, innerFunction: P => List[String]): List[String] =
innerFunction(person)
outerFunction(myUser, innerFunctionForUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin, innerFunctionForAdmin) //List(178789, jack, high)
您也可以尝试将函数 innerFunctionForUser
、innerFunctionForAdmin
替换为 type class
trait InnerFunction[P <: Person] {
def apply(person: P): List[String]
}
object InnerFunction {
implicit val forUser: InnerFunction[User] =
user => List(user.uid, user.firstname, user.active)
implicit val forAdmin: InnerFunction[Admin] =
admin => List(admin.id, admin.pseudo, admin.securityClearance)
}
def outerFunction[P <: Person](person: P)(implicit innerFunction: InnerFunction[P]): List[String] =
innerFunction(person)
outerFunction(myUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin) //List(178789, jack, high)
由于类型 class InnerFunction
现在对不同数据类型的作用相似(它为一个案例的所有字段生成值列表 class),您甚至可以 导出它:
trait InnerFunction[T] {
def apply(t: T): List[String]
}
object InnerFunction {
implicit def mkInnerFunction[T <: Product]: InnerFunction[T] =
_.productIterator.map(_.asInstanceOf[String]).toList
}
def outerFunction[T](t: T)(implicit innerFunction: InnerFunction[T]): List[String] =
innerFunction(t)
//or simply
// def outerFunction[T <: Product](t: T): List[String] =
// t.productIterator.map(_.asInstanceOf[String]).toList
//or
// def outerFunction(t: Product): List[String] =
// t.productIterator.map(_.asInstanceOf[String]).toList
outerFunction(myUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin) //List(178789, jack, high)
(如果不是 T
的所有字段都是 String
s,这将在运行时失败)or
import shapeless.ops.hlist.ToList
import shapeless.{Generic, HList}
trait InnerFunction[T] {
def apply(t: T): List[String]
}
object InnerFunction {
implicit def mkInnerFunction[T <: Product, L <: HList](implicit
generic: Generic.Aux[T, L],
toList: ToList[L, String]
): InnerFunction[T] = generic.to(_).toList
}
def outerFunction[T](t: T)(implicit innerFunction: InnerFunction[T]): List[String] =
innerFunction(t)
//or simply
// def outerFunction[T, L <: HList](t: T)(implicit
// generic: Generic.Aux[T, L],
// toList: ToList[L, String]
// ): List[String] = generic.to(t).toList
outerFunction(myUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin) //List(178789, jack, high)
(这将在编译时保证T
的所有字段都是String
)。
对不起,我找不到更好的标题。
我正在努力实现如下目标
abstract class Person
case class User(uid: String, firstname: String, active: String) extends Person
case class Admin(id: String, pseudo: String, securityClearance: String) extends Person
def innerFunctionForUser(user: User): List[String] = {
List() :+ user.uid :+ user.firstname :+ user.active
}
def innerFunctionForAdmin(admin: Admin): List[String] = {
List() :+ admin.id :+ admin.psuedo :+ admin.securityClearance
}
def outerFunction(person: Person, innerFunction: (Person) => List[String]): List[String] = {
innerFunction(person)
}
所以我可以像那样使用它
val myUser = User("0c60c5b4-306d-4372-b60d-fd699c80e408", "joe", "false")
val myAdmin = Admin("178789", "jack", "high")
outerFunction(myUser, innerFunctionForUser)
outerFunction(myAdmin, innerFunctionForAdmin)
没有类型检查
type mismatch;
found : User => List[String]
required: Person => List[String]
而且我不能让 innerFunction 接受这样的人
def innerFunctionForUser(user: Person): List[String] = {
List() :+ user.uid :+ user.firstname :+ user.active
}
我在这里保持简单,但我需要 case class 具有不同类型的参数和不同数量的参数。 所以我不能在摘要 class Person 中声明它们。 这会给
value uid is not a member of Person
value firstname is not a member of Person
value active is not a member of Playground.Person
如何使类型和数字参数不同的不同案例 class 的计算结果相同?
AND/OR
如何使回调多态,像这样
def outerFunction(person: Person, innerFunction: (SomeCaseClass) => List[String]): List[String] = {
innerFunction(person)
}
希望这已经够清楚了。
感谢阅读,祝您玩得愉快。
User
和 Admin
是 Person
的子类型,但 User => List[String]
和 Admin => List[String]
不是 的子类型 Person => List[String]
。 User => List[String]
和 Admin => List[String]
实际上是 Person => List[String]
的 超类型 。函数类型 A => B
相对于 B
是 covariant 但相对于 A
.
努力做到outerFunction
generic
def outerFunction[P <: Person](person: P, innerFunction: P => List[String]): List[String] =
innerFunction(person)
outerFunction(myUser, innerFunctionForUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin, innerFunctionForAdmin) //List(178789, jack, high)
您也可以尝试将函数 innerFunctionForUser
、innerFunctionForAdmin
替换为 type class
trait InnerFunction[P <: Person] {
def apply(person: P): List[String]
}
object InnerFunction {
implicit val forUser: InnerFunction[User] =
user => List(user.uid, user.firstname, user.active)
implicit val forAdmin: InnerFunction[Admin] =
admin => List(admin.id, admin.pseudo, admin.securityClearance)
}
def outerFunction[P <: Person](person: P)(implicit innerFunction: InnerFunction[P]): List[String] =
innerFunction(person)
outerFunction(myUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin) //List(178789, jack, high)
由于类型 class InnerFunction
现在对不同数据类型的作用相似(它为一个案例的所有字段生成值列表 class),您甚至可以 导出它:
trait InnerFunction[T] {
def apply(t: T): List[String]
}
object InnerFunction {
implicit def mkInnerFunction[T <: Product]: InnerFunction[T] =
_.productIterator.map(_.asInstanceOf[String]).toList
}
def outerFunction[T](t: T)(implicit innerFunction: InnerFunction[T]): List[String] =
innerFunction(t)
//or simply
// def outerFunction[T <: Product](t: T): List[String] =
// t.productIterator.map(_.asInstanceOf[String]).toList
//or
// def outerFunction(t: Product): List[String] =
// t.productIterator.map(_.asInstanceOf[String]).toList
outerFunction(myUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin) //List(178789, jack, high)
(如果不是 T
的所有字段都是 String
s,这将在运行时失败)or
import shapeless.ops.hlist.ToList
import shapeless.{Generic, HList}
trait InnerFunction[T] {
def apply(t: T): List[String]
}
object InnerFunction {
implicit def mkInnerFunction[T <: Product, L <: HList](implicit
generic: Generic.Aux[T, L],
toList: ToList[L, String]
): InnerFunction[T] = generic.to(_).toList
}
def outerFunction[T](t: T)(implicit innerFunction: InnerFunction[T]): List[String] =
innerFunction(t)
//or simply
// def outerFunction[T, L <: HList](t: T)(implicit
// generic: Generic.Aux[T, L],
// toList: ToList[L, String]
// ): List[String] = generic.to(t).toList
outerFunction(myUser) //List(0c60c5b4-306d-4372-b60d-fd699c80e408, joe, false)
outerFunction(myAdmin) //List(178789, jack, high)
(这将在编译时保证T
的所有字段都是String
)。