加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 建模两种类型之间的二元关系

发布时间:2020-12-16 18:12:26 所属栏目:安全 来源:网络整理
导读:有企业和人.用户可以喜欢或发布关于商家的评论,但对于一个人来说也不会发生同样的事情.当用户发布有关某个商家或喜欢它的内容时,该商家会被称为该商家的目标: trait TargetingRelation[TargetingType[_],TargetedType]class Businessclass Personclass Post
有企业和人.用户可以喜欢或发布关于商家的评论,但对于一个人来说也不会发生同样的事情.当用户发布有关某个商家或喜欢它的内容时,该商家会被称为该商家的目标:

trait TargetingRelation[TargetingType[_],TargetedType]

class Business

class Person

class Post[Target | TargetingRelation[Business,Post] ] {
  def target:Target
}

class Like[Target | TargetingRelation[Business,Like] ] {
  def target:Target
}

在这里,我发明了一个T | P [T]符号表示类型参数T,使得它满足某些属性P [T](或T:|:P [T],如果它携带更多的类型吸引力).代码中的其他地方我想要声明如下:

object canPostAboutBusiness extends TargetingRelation[Post,Business] 
object canLikeBusiness      extends TargetingRelation[Like,Business]

这些对象实际上是证据,类似于Haskell类型类.所以这会打字检查:

val p = new Post[Business]
val l = new Like[Business]

但不是这个:

val p = new Post[Person]
val l = new Like[Person]

就我对Scala的认识而言,我无法以令人满意的方式对这种特殊情况进行建模.现在我坚持认为这不是子类型,因为商业不是:

class Business extends 
  TargetingRelation[Post,Business] with 
  TargetingRelation[Like,Business]

事实上,商业仍然完全不了解邮政是非常可取的.这种关系实际上不属于邮政和商业.此外,我认为上面的代码甚至不会编译开始,因为Business继承了两次TargetingRelation.很受欢迎.

相关:Using a context bound in a class type parameter

解决方法

您可以在scala中执行此操作,其中某些操作类似于使用implicits的类型类.例如:

import scala.language.higherKinds

trait TargetingRelation[A[_],B]

class Business
class Person

// Using explicitly declared implicit parameter:
class Post[T](implicit ev: TargetingRelation[Post,T])

// Using a "context bound". The syntax is a little hairy and uses
// a type lambda because TargetingRelation takes multiple type params
class Like[T : ({type S[x] = TargetingRelation[Like,x]})#S]

implicit object canPostAboutBusiness extends TargetingRelation[Post,Business]
implicit object canLikeBusiness      extends TargetingRelation[Like,Business]

然后,您可以使用Business实例化类

scala> val p = new Post[Business]
p: Post[Business] = Post@374c991a

scala> val l = new Like[Business]
l: Like[Business] = Like@1fd348f8

但不是与人

scala> val p1 = new Post[Person]
<console>:15: error: could not find implicit value for parameter ev: TargetingRelation[Post,Person]
       val p1 = new Post[Person]
                ^

scala> val p2 = new Like[Person]
<console>:15: error: could not find implicit value for evidence parameter of type TargetingRelation[Post,Person]
       val p2 = new Like[Person]
                ^

如果你从“scala类型类”中搜索,你会发现大量的explanations of the details如何工作,但基本上,你需要构造函数采用TargetingRelation [TargetingType [_],TargetedType]类型的隐式参数,然后放置一个隐含的在构造类(Post或Like)时范围内的那种类型.隐式用作“证据”,即TargetedType具有类型类的实例(并且扮演在其他语言类型类实现中自动传递的显式方法字典的角色).

事实上,scala有一些同步糖可以帮助解决这个问题,称为Context Bound.这导致方法写成:

def a[A: B] = ???

被翻译成

def a[A](implicit ev: B[A]) = ???

在您的特定示例中,上下文边界语法有点棘手,因为有多个类型参数,但可以按照this SO question描述的那样完成.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读