我认为我的问题与此问题相关但不相同here。
让我们定义我的第一堂课
case class NoteTaker() {
private var note: Seq[String] = Seq("\n")
override def toString: String = this.note.mkString("\n")
def add(newNote: String): Unit = note ++= Seq(newNote)
}
现在我有一个特质
trait SilentLogger {
import scala.util.{ Failure, Success }
val notepad = NoteTaker()
def tryAndLog[X, Y](x: X, f: X => Y): Y = {
notepad.add("Run with this input: " + x.toString)
(try {
println("Before: " + notepad.toString)
val result = f(x)
println("After: " + notepad.toString)
notepad.add("Get result:-------------------------------\n" + result.toString)
println(notepad.toString)
Success(result)
} catch {
case e: Throwable => {
println(
"Exception occurs:" + "\n" +
notepad.toString + "\n" +
e.getMessage + "\n" +
e.getStackTrace.mkString("\n")
)
Failure(e)
}}).get
}
}
我打算使用这个特性来混合我想要收集一些笔记的任何类,并且只有在出现异常时才打印出笔记。否则,我可能只是将它保存到某个日志文件中。
我想要创建一次记事本,并为每个对象重复使用。事实上,我不介意他们是否共享相同的记事本。因此,我选择在我的特质中使用'val'。
作为一个例子,我然后创建一个类
case class MyClass (myField : String) extends SilentLogger {
def makeAnother : MyClass = tryAndLog("makeAnother",(x: String) => {
notepad.add(x)
val result = this.copy(myField = this.myField + " addNewField " + x)
notepad.add(result.myField)
return result
})
}
最后我尝试创建两个对象:
scala> val firstObject = MyClass("firstObject")
firstObject: MyClass = MyClass(firstObject)
scala> val secondObject = firstObject.makeAnother
Before:
Run with this input: makeAnother
Exception occurs:
Run with this input: makeAnother
makeAnother
firstObject addNewField makeAnother
null
secondObject: MyClass = MyClass(firstObject addNewField makeAnother)
我真的很困惑。显然发生了异常。但是第二个对象创建得很好吗?但是日志消息在stdout上打印出来,错误为“null”。
我认为我的问题是我的第一个和第二个对象实际上是使用相同的记事本还是分开?如何在此处定义初始化和记事本的范围?我使用'尝试'的方式有问题吗?
答案 0 :(得分:1)
这是由明确return
的匿名函数引起的:
(x: String) => {
notepad.add(x)
val result = this.copy(myField = this.myField + " addNewField " + x)
notepad.add(result.myField)
return result
}
在 Scala 中,当在匿名函数中明确声明return
时,它会抛出NonLocalReturnControl,这将跳过后面的代码阻止执行,因为您已抓住Throwable
,因此它也将转到您的catch code block
。
所以也许你可以直接删除return
来解决这个问题。