我正在寻找一种限制某些对象调用的方法。给定一个事务系统,它定义了一个引用类型,一个事务类型和一个标识符:
trait Sys[S <: Sys[S]] {
type Ref[A]
type Tx <: Txn[S]
type ID
}
我希望能够混合一个可用于创建可变引用的特征:
trait Mutable[S <: Sys[S]] {
def id: S#ID
protected final def newRef[A](implicit tx: S#Tx): S#Ref[A] =
tx.newRef[A](this)
}
参考工厂被定义为交易的一部分:
trait Txn[S <: Sys[S]] {
/* private[Mutable] */ def newRef[A](mut: Mutable[S]): S#Ref[A]
def newID: S#ID
}
现在,问题是,在以下结构中,我可以创建具有错误上下文的引用:
def newStruct[S <: Sys[S]](cross: Mutable[S])(implicit tx: S#Tx) =
new Mutable[S] {
val id = tx.newID
val allowed = newRef[Int]
val forbidden = tx.newRef[Int](cross) // shouldn't compile...
}
我想不允许最后一次通话。显然,我无法将newRef
Txn
私有Mutable
,因为Mutable
不是Txn
的封闭类。我也不想使用包隐私,因为通过在该包中定义一个对象,可以很容易地进入newRef
。
理想情况下我想这样:
trait Sys[S <: Sys[S]] { trait Mutable }
class MyStruct[S <: Sys[S]] extends S#Mutable { ... }
这将解决所有问题。但这是不允许的,因为scalac宇宙中的S
S#Mutable
中的"is not a legal prefix for a constructor"
....
感谢您的建议!
答案 0 :(得分:2)
您可以将Txn
的定义放在Mutable
的伴随对象中,然后将其设为私有Mutable
。但不确定是否还有其他影响。
trait Sys[ S <: Sys[ S ]] {
type Ref[ A ]
type Tx <: Txn[ S ]
type ID
}
object Mutable {
trait Txn[ S <: Sys[ S ]] {
private[Mutable] def newRef[ A ]( mut: Mutable[ S ]) : S#Ref[ A ]
def newID : S#ID
}
}
trait Mutable[ S <: Sys[ S ]] {
def id: S#ID
protected final def newRef[ A ]( implicit tx: S#Tx ) : S#Ref[ A ] =
tx.newRef[ A ]( this )
}
// Or maybe you could declare type Txn in the package object...
trait Txn[ S <: Sys[ S ]] extends Mutable.Txn[S]
object Foo {
def newStruct[ S <: Sys[ S ]]( cross: Mutable[ S ])( implicit tx: S#Tx ) =
new Mutable[ S ] {
val id = tx.newID
val allowed = newRef[ Int ]
val forbidden = tx.newRef[ Int ]( cross ) // doesn't compile...
}
}