scala 如何在*每个实例*中*没有*引用记录器的情况下登录Scala?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6466190/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to log in Scala *without* a reference to the logger in *every instance*?
提问by Sebastien Diot
I've looked at example of logging in Scala, and it usually looks like this:
我看过登录 Scala 的例子,它通常是这样的:
import org.slf4j.LoggerFactory
trait Loggable {
private lazy val logger = LoggerFactory.getLogger(getClass)
protected def debug(msg: => AnyRef, t: => Throwable = null): Unit =
{...}
}
This seems independent of the concrete logging framework. While this does the job, it also introduces an extraneous lazy val in every instancethat wants to do logging, which might well be every instance of the whole application. This seems much too heavy to me, in particular if you have many "small instances" of some specific type.
这似乎独立于具体的日志记录框架。虽然这样做可以完成工作,但它也会在每个想要进行日志记录的实例中引入一个无关的惰性 val ,这很可能是整个应用程序的每个实例。这对我来说似乎太重了,特别是如果您有许多特定类型的“小实例”。
Is there a way of putting the logger in the object of the concrete class instead, just by using inheritance? If I have to explicitly declare the logger in the object of the class, and explicitly refer to it from the class/trait, then I have written almost as much code as if I had done no reuse at all.
有没有办法将记录器放在具体类的对象中,只需使用继承?如果我必须在类的对象中显式声明记录器,并从类/特征中显式引用它,那么我编写的代码几乎和我根本没有重用一样多。
Expressed in a non-logging specific context, the problem would be:
在非日志记录的特定上下文中表示,问题将是:
How do I declare in a trait that the implementing class must have a singleton object of type X, and that this singleton object must be accessible through method def x: X ?
我如何在特性中声明实现类必须有一个 X 类型的单例对象,并且这个单例对象必须可以通过方法 def x: X 访问?
I can't simply define an abstract method, because there could only be a single implementation in the class. I want that logging in a super-class gets me the super-class singleton, and logging in the sub-class gets me the sub-class singleton. Or put more simply, I want logging in Scala to work like traditional logging in Java, using static loggers specific to the class doing the logging. My current knowledge of Scala tells me that this is simply not possible without doing it exactly the same way you do in Java, without much if any benefits from using the "better" Scala.
我不能简单地定义抽象方法,因为类中只能有一个实现。我希望登录超类让我获得超类单例,而登录子类让我获得子类单例。或者更简单地说,我希望在 Scala 中的日志记录像 Java 中的传统日志记录一样工作,使用特定于执行日志记录的类的静态记录器。我目前对 Scala 的了解告诉我,如果不按照您在 Java 中所做的完全相同的方式进行操作,这是不可能的,使用“更好的”Scala 并没有太多好处。
采纳答案by Stefan De Boey
How do I declare in a trait that the implementing class must have a singleton object of type X, and that this singleton object must be accessible through method def x: X ?
我如何在特性中声明实现类必须有一个 X 类型的单例对象,并且这个单例对象必须可以通过方法 def x: X 访问?
Declare a trait that must be implemented by your companion objects.
声明一个必须由你的伴生对象实现的特征。
trait Meta[Base] {
val logger = LoggerFactory.getLogger(getClass)
}
Create a base trait for your classes, sub-classes have to overwrite the meta method.
为您的类创建一个基本特征,子类必须覆盖元方法。
trait Base {
def meta: Meta[Base]
def logger = meta.logger
}
A class Whatever with a companion object:
带有伴生对象的类 What :
object Whatever extends Meta[Base]
class Whatever extends Base {
def meta = Whatever
def doSomething = {
logger.log("oops")
}
}
In this way you only need to have a reference to the meta object.
通过这种方式,您只需要引用元对象。
We can use the Whatever class like this.
我们可以像这样使用 What 类。
object Sample {
def main(args: Array[String]) {
val whatever = new Whatever
whatever.doSomething
}
}
回答by oxbow_lakes
Premature Optimization is the root of all evil
过早优化是万恶之源
Let's be clear first about one thing: if your trait looks something like this:
让我们先弄清楚一件事:如果你的特征看起来像这样:
trait Logger { lazy val log = Logger.getLogger }
Then what you have notdone is as follows:
那么你没有做的如下:
- You have NOTcreated a logger instance per instance of your type
- You have neither given yourself a memory nor a performance problem (unless you have)
- 你已经不是创造你的每个类型的实例的记录器实例
- 你既没有给自己一个记忆也没有性能问题(除非你有)
What you havedone is as follows:
你已经做了如下:
- You have an extra referencein each instance of your type
- When you access the logger for the first time, you are probably doing some map lookup
- 您在您的类型的每个实例中都有一个额外的参考
- 当您第一次访问记录器时,您可能正在执行一些地图查找
Note that, even if you did create a separate logger for each instance of your type(which I frequently do, even if my program contains hundreds of thousands of these, so that I have very fine-grained control over my logging), you almost certainly still will neither have a performance nor a memory problem!
请注意,即使您确实为您的类型的每个实例创建了一个单独的记录器(我经常这样做,即使我的程序包含数十万个这样的记录,以便我对我的日志记录进行非常细粒度的控制),您几乎当然仍然不会有性能和内存问题!
One "solution" is (of course), to make the companion object implement the logger interface:
一个“解决方案”是(当然),使伴随对象实现记录器接口:
object MyType extends Logger
class MyType {
import MyType._
log.info("Yay")
}
回答by Debilski
I think you cannot automatically get the corresponding singleton object of a class or require that such a singleton exists.
我认为您无法自动获取类的相应单例对象或要求存在这样的单例。
One reason is that you cannot know the type of the singleton before it is defined. Not sure, if this helps or if it is the best solution to your problem, but if you want to require some meta object to be defined with a specific trait, you could define something like:
原因之一是您无法在定义之前知道单例的类型。不确定,如果这有帮助或者它是否是您问题的最佳解决方案,但如果您想要求使用特定特征定义一些元对象,您可以定义如下内容:
trait HasSingleton[Traits] {
def meta: Traits
}
trait Log {
def classname: String
def log { println(classname) }
}
trait Debug {
def debug { print("Debug") }
}
class A extends HasSingleton[Log] {
def meta = A // Needs to be defined with a Singleton (or any object which inherits from Log}
def f {
meta.log
}
}
object A extends Log {
def classname = "A"
}
class B extends HasSingleton[Log with Debug] { // we want to use Log and Debug here
def meta = B
def g {
meta.log
meta.debug
}
}
object B extends Log with Debug {
def classname = "B"
}
(new A).f
// A
(new B).g
// B
// Debug
回答by agilesteel
I'm not sure I understand your question completely. So I apologize up front if this is not the answer you are looking for.
我不确定我是否完全理解你的问题。因此,如果这不是您正在寻找的答案,我会预先道歉。
Define an objectwere you put your loggerinto, then create a companion trait.
定义一个object你投入logger进去的地方,然后创建一个伴侣trait。
object Loggable {
private val logger = "I'm a logger"
}
trait Loggable {
import Loggable._
def debug(msg: String) {
println(logger + ": " + msg)
}
}
So now you can use it like this:
所以现在你可以像这样使用它:
scala> abstract class Abstraction
scala> class Implementation extends Abstraction with Loggable
scala> val test = new Implementation
scala> test.debug("error message")
I'm a logger: error message
Does this answer your question?
这回答了你的问题了吗?

![scala 从列表中产生字符串[Char]](/res/img/loading.gif)