有企业和人。用户可以喜欢或发布关于某个商家的评论,但同一个人不能。当用户发布有关某个商家或喜欢该商家的内容时,该商家称为target
,或者发布:{/ p>
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的认识而言,我无法以令人满意的方式模拟这种特殊情况。现在我坚持认为这是不子类型,因为商家不 a:
class Business extends
TargetingRelation[Post,Business] with
TargetingRelation[Like,Business]
事实上,Business
仍然完全不了解Post
,这是非常可取的。这种关系实际上在Post
和Business
之外。此外,我认为上面的代码甚至不会编译开始,因为Business
从TargetingRelation
继承两次。很受欢迎。
答案 0 :(得分:6)
你可以在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
但不是Person
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描述时完成。