[英]Little help needed with structural typing
I noticed the repeating pattern in my code, and thought this may be a good idea to give structural typing a try. 我注意到代码中的重复模式,并认为尝试结构化输入可能是一个好主意。 I've read the chapter ;-), but I can't quite get my head around it.
我已经阅读了这一章;-)但我无法理解它。 Consider the following code:
请考虑以下代码:
def link(user: User, group: Group) = {
UserGroupLinks.insert((user.id, group.id))
}
def link(group: Group, role: Role) = {
GroupRoleLinks.insert((group.id, role.id))
}
def link(user: User, role: Role) = {
UserRoleLinks.insert((user.id, role.id))
}
How do I combine it into something like: 如何将其组合成以下内容:
def link(A <: ...something with an id, B<:... something with and id) = {
(A, B) match {
case (u: User, g: Group) => UserGroupLinks.insert((user.id, group.id))
case (g: Group, r: Role) => GroupRoleLinks.insert((group.id, role.id))
case (u: User, r: Role) => UserRoleLinks.insert((user.id, role.id))
case _ =>
}
}
With structural types it would be something like this: 对于结构类型,它将是这样的:
type WithId = {def id:Int}
def link(a:WithId, b:WithId) =
(a, b) match {
case (u:User, g:Group) => UserGroupLinks.insert(u.id -> g.id)
case _ =>
}
You could go a bit further and let the compiler help you with selecting the correct inserter. 您可以更进一步,让编译器帮助您选择正确的插入器。 For that you would need to introduce a trait on your inserters:
为此你需要在你的插入器上引入一个特性:
trait WithInsert[A, B] {
def insert(x: (Int, Int)): Unit
}
And then on your insert objects do this: 然后在插入对象上执行以下操作:
object UserGroupLinks extends WithInsert[User, Group]
You can define the default ones on the companion object 您可以在随播对象上定义默认值
object WithInsert {
implicit val ug = UserGroupLinks
implicit val gr = GroupRoleLinks
}
We can still use the WithId
type although in most cases I would recommend using a trait 我们仍然可以使用
WithId
类型,但在大多数情况下我会建议使用特征
type WithId = { def id: Int }
Your link method then would look like this: 您的链接方法将如下所示:
def link[A <: WithId, B <: WithId](a: A, b: B)(implicit inserter: WithInsert[A, B]) =
inserter.insert(a.id -> b.id)
As you can see the link method expects a WithInsert[A, B]
to be available. 正如您所看到的,link方法需要一个
WithInsert[A, B]
。 It will find the appropriate one in the companion object of WithInsert
. 它将在
WithInsert
的伴随对象中找到合适的对象。
That means you can now call your method simply like this: 这意味着您现在可以像这样调用您的方法:
link(user, group)
link(group, role)
This is the simple solution I was looking for: 这是我正在寻找的简单解决方案:
def link[A <: { def id: Long }, B <: { def id: Long }](a: A, b: B) = {
(a, b) match {
case (u: User, g: Group) => UserGroupLinks.insert((u.id, g.id))
case (g: Group, r: Role) => GroupRoleLinks.insert((g.id, r.id))
case (u: User, r: Role) => UserRoleLinks.insert((u.id, r.id))
case _ => ???
}
}
Where the compiler would allow: 编译器允许的地方:
case class XX(id: Long)
case class YY(id: Long)
case class ZZ(idz: Long)
link(XX(22), YY(33))
But not: 但不是:
link(XX(22), ZZ(33))
Try 尝试
type T = { val id: String }
def link(obj1 : T, obj2: T) = {
// You got
println(" obj1.id = %s obj2.id = %s".format(obj1.id, obj2.id))
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.