如果不评论这个的智慧(我认为这取决于),没有什么能阻止你在你的隐式参数上提供默认参数。如果你这样做,一个已解析的隐式将优先,但如果没有找到隐式,将使用默认参数。
但是,无论如何,您的withTx
函数都不起作用,因为您定义的隐式不在功能块的范围内。(你不可能tx
从你在那里定义的函数中引用。)
要修改您的示例(给交易一个标签以明确这一点):
class Foo {
var m = scala.collection.mutable.HashMap.empty[String, String]
case class Tx(label : String, mcopy: scala.collection.mutable.HashMap[String, String]) {
def commit = (m = mcopy)
def rollback = () // not copying mcopy will lose all changes made to it
}
def withTx(block: Foo => Unit): Unit = {
implicit val tx = new Tx("oopsy", m.clone)
try {
block(this)
tx.commit
} catch {
case _: Throwable => tx.rollback
}
}
implicit val emptyTx = new Tx("passthrough", m) // non-tx operations will be performed directly on 'm'
def add(k: String, v: String)(implicit t: Tx = emptyTx): Unit = {
println( t )
t.mcopy += k -> v
}
}
然后...
scala> val f = new Foo
f: Foo = Foo@3e1f13d2
scala> f.add( "hi", "there" )
Tx(passthrough,Map())
scala> implicit val tx = new f.Tx( "outside", scala.collection.mutable.HashMap.empty )
tx: f.Tx = Tx(outside,Map())
scala> f.add( "bye", "now" )
Tx(outside,Map())
但是你的 withTx(...) 函数并没有做你想做的事,现在,无济于事的是,它并没有引起人们注意它没有引起你想要的错误的事实。它只是做错事。in 的操作不是获取不在范围内的隐式值,而是block
获取默认参数,这与您的意图相反。
scala> f.withTx( foo => foo.add("bye", "now") )
Tx(passthrough,Map(bye -> now, hi -> there))
更新:
要获得所需的withTx
方法,您可以尝试:
def withTx(block: Tx => Unit): Unit = {
val tx = new Tx("hooray", m.clone)
try {
block(tx)
tx.commit
} catch {
case _: Throwable => tx.rollback
}
}
用户需要将提供的交易标记为implicit
在他们的块中。它会是这样的:
scala> val f = new Foo
f: Foo = Foo@41b76137
scala> :paste
// Entering paste mode (ctrl-D to finish)
f.withTx { implicit tx =>
f.add("boo","hoo")
tx.commit
}
// Exiting paste mode, now interpreting.
Tx(hooray,Map()) // remember, we print the transaction before adding to the map, just to verify the label
scala> println(f.m)
Map(boo -> hoo)
所以这“有效”。但实际上,由于您在块完成后自动提交,除非它以异常完成,否则我对 tx.commit 的调用是不必要的。
我不认为这是一个很好的选择。看这个:
scala> :paste
// Entering paste mode (ctrl-D to finish)
f.withTx { implicit tx =>
f.add("no","no")
tx.rollback
}
// Exiting paste mode, now interpreting.
Tx(hooray,Map(boo -> hoo)) // remember, we print the transaction before adding to the map, just to verify the label
scala> println(f.m)
Map(no -> no, boo -> hoo)
尽管add(...)
我明确要求完成rollback
!那是因为这rollback
只是一个空操作,然后是一个自动提交。
要真正看到回滚,您需要抛出一个Exception
:
scala> :paste
// Entering paste mode (ctrl-D to finish)
f.withTx { implicit tx =>
f.add("really","no")
throw new Exception
}
// Exiting paste mode, now interpreting.
Tx(hooray,Map(no -> no, boo -> hoo)) // remember, we print the transaction before adding to the map, just to verify the label
scala> println(f.m)
Map(no -> no, boo -> hoo)
现在,终于,我们可以看到对它的调用add(...)
被恢复了。