简体   繁体   English

如何在Scala中继承相同特征的两个对象中初始化val?

[英]How val is initialised in two objects inheriting the same trait in scala?

I think my question is related but not the same as this one here . 我认为我的问题是相关的,但与这里的问题不同

Let define my first class 让我们定义我的第一堂课

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)
}

Now I have a trait 现在我有一个特质

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
}
}

I intend to use this trait to mix in with any classes where I want to collect some notes and only print out the note when there is an exception. 我打算将此特征与我想收集一些笔记的任何类混合使用,并且仅在出现异常时才打印出笔记。 Otherwise, I maybe just save it to a log file somewhere. 否则,我可能只是将其保存到某个地方的日志文件中。

I want the notepad to be created once and reused for each of the object. 我希望记事本一次创建一次,并且可以为每个对象重复使用。 In fact, I don't mind if they share the same notepad. 实际上,我不介意它们是否共享同一个记事本。 Therefore, I chose to use 'val' in my trait. 因此,我选择在特征中使用“ val”。

As an example, I then create a class 例如,然后我创建一个类

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
    })
}

And finally I try to create two objects as follow: 最后,我尝试创建两个对象,如下所示:

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)

I'm really confused here. 我真的很困惑。 Obviously an exception occurred. 显然发生了异常。 But the secondObject was created just fine? 但是创建第二对象好吗? But the logging message get printed out on stdout with the error 'null'. 但是,日志记录消息会在标准输出上打印出来,错误为“ null”。

I think my question is whether my first and second objects are actually using the same notepad or separate? 我认为我的问题是我的第一个和第二个对象实际上是使用同一记事本还是分开使用? How are the initialisation and the scope of notepad defined here? 记事本的初始化和范围如何定义? Is there something wrong with the way I use 'Try'? 我使用“尝试”的方式有什么问题吗?

This is caused of anonymous function with explicitly return : 这是由匿名函数引起的,具有显式return

   (x: String) => {
        notepad.add(x)
        val result = this.copy(myField = this.myField + " addNewField " + x)
        notepad.add(result.myField)
        return result
    }

In Scala , when explicitly declare return in anonymous function , it will throw NonLocalReturnControl , this will skip the later code block execute, since you have catched the Throwable , so it also will go to your catch code block . Scala中 ,当使用匿名函数显式声明return时,它将抛出NonLocalReturnControl ,这将跳过以后的代码块执行,因为您已经catch code blockThrowable ,因此它也将转到您的catch code block

So maybe you can remove return directly to solve this issue. 因此,也许您可​​以直接删除return来解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM