Scala多态回调类型不匹配 [英] Scala polymorphic callback type mismatch

查看:68
本文介绍了Scala多态回调类型不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,我找不到更好的标题。

I'm sorry i couldn't find a better title.

我正在尝试实现以下目标

I'm trying to achieve something like the following

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接受这样的类型的人

and i can't have the innerFunction accept a type person like this

def innerFunctionForUser(user: Person): List[String] = {
  List() :+ user.uid :+ user.firstname :+ user.active
}

我在这里保持简单,但是我需要带有不同类型和不同数量参数的case类。
所以我不能在抽象类Person中声明它们。
这将给

I kept it simple here but i need case class with parameters of different type and different number of parameters. So i can't have them declared in the abstract class Person. Which would give

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

如何一个使不同大小写的类在类型和数字上具有不同参数的值求和为同一类型?

How can one make different case class with different parameters in types and numbers evaluate to the same type ?

AND / OR

如何使a回调多态,类似这样

How can one make a a callback polymorphic, kind a like this

def outerFunction(person: Person, innerFunction: (SomeCaseClass) => List[String]): List[String] = {
  innerFunction(person)
}

希望这很清楚。

感谢阅读,祝您阅读愉快。

Thanks for reading, Have a good One.

推荐答案

User Admin Person 的子类型,但 User => List [String] Admin => List [String] 不是 Person =>的子类型。列表[String] 用户=> List [String] Admin => List [String] 实际上是 Person =>的超类型。列表[String] 。函数类型 A => B 对于<$ c是协变 $ c> B ,但与 A 相反。

User and Admin are subtypes of Person but User => List[String] and Admin => List[String] are not subtypes of Person => List[String]. User => List[String] and Admin => List[String] are actually supertypes of Person => List[String]. Function type A => B is covariant with respect to B but contravariant with respect to A.

尝试使 outerFunction 通用

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 类型类

You can also try to replace functions innerFunctionForUser, innerFunctionForAdmin with 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)

由于类型类 InnerFunction 现在类似地作用于不同的数据类型(它为案例类的所有字段生成值列表),甚至可以推导它:

Since type class InnerFunction acts on different data types now similarly (it produces list of values for all fields of a case class) you can even derive it:

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,则在运行时将失败)

(this will fail at runtime if not all fields of T are Strings) 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)

(this将在编译时保证 T 的所有字段都是 String s)。

(this will guarantee at compile time that all fields of T are Strings).

这篇关于Scala多态回调类型不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆