class 方法隐式参数的默认值
Default value for implicit parameter of class method
我想要一种 "transaction" 结构,我在其上进行所有更改,然后决定最后是提交还是回滚。我的问题是我不知道如何正确定义/传递隐式值而不从调用函数的地方手动定义它们。如何实现?
class Foo {
var m = scala.collection.mutable.HashMap.empty[String, String]
case class Tx(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(m.clone)
try {
block(this)
tx.commit
} catch {
case _: Throwable => tx.rollback
}
}
implicit val emptyTx = new Tx(m) // non-tx operations will be performed directly on 'm'
def add(k: String, v: String)(implicit t: Tx): Unit = (t.mcopy += k -> v)
}
val f = new Foo
f.add("k0", "v0") // error: no implicit t defined...
f.withTx { foo => foo.add("k1", "v1") } // errors as well on missing implicit
您可以像这样在单独的特征或对象中定义隐式变量:
trait MyImplicits {
implicit val myImplicitParameter: Int = 0
}
trait MyInterface {
def implicitMethod(a:Int)(implicit b: Int) = ???
}
object MyClass extends MyInterface with MyImplicits {
def main(args: Array[String]) = {
implicitMethod(1)
}
}
在不评论这个智慧的情况下(我认为这取决于),没有什么能阻止你为你的隐式参数提供默认参数。如果这样做,已解析的隐式将优先,但如果未找到隐式,将使用默认参数。
但是,无论如何,您的 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(...) 函数没有做你想做的事,现在,毫无帮助的是,它没有提醒你注意它没有做你想做的事并出现错误。它只是做错了事。 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)
所以"worked"。但实际上,由于您在块完成后自动提交,除非它以异常完成,否则我对 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)
尽管我明确调用了 rollback
,add(...)
还是完成了!那是因为 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(...)
的调用被还原了。
我想要一种 "transaction" 结构,我在其上进行所有更改,然后决定最后是提交还是回滚。我的问题是我不知道如何正确定义/传递隐式值而不从调用函数的地方手动定义它们。如何实现?
class Foo {
var m = scala.collection.mutable.HashMap.empty[String, String]
case class Tx(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(m.clone)
try {
block(this)
tx.commit
} catch {
case _: Throwable => tx.rollback
}
}
implicit val emptyTx = new Tx(m) // non-tx operations will be performed directly on 'm'
def add(k: String, v: String)(implicit t: Tx): Unit = (t.mcopy += k -> v)
}
val f = new Foo
f.add("k0", "v0") // error: no implicit t defined...
f.withTx { foo => foo.add("k1", "v1") } // errors as well on missing implicit
您可以像这样在单独的特征或对象中定义隐式变量:
trait MyImplicits {
implicit val myImplicitParameter: Int = 0
}
trait MyInterface {
def implicitMethod(a:Int)(implicit b: Int) = ???
}
object MyClass extends MyInterface with MyImplicits {
def main(args: Array[String]) = {
implicitMethod(1)
}
}
在不评论这个智慧的情况下(我认为这取决于),没有什么能阻止你为你的隐式参数提供默认参数。如果这样做,已解析的隐式将优先,但如果未找到隐式,将使用默认参数。
但是,无论如何,您的 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(...) 函数没有做你想做的事,现在,毫无帮助的是,它没有提醒你注意它没有做你想做的事并出现错误。它只是做错了事。 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)
所以"worked"。但实际上,由于您在块完成后自动提交,除非它以异常完成,否则我对 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)
尽管我明确调用了 rollback
,add(...)
还是完成了!那是因为 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(...)
的调用被还原了。