我是scala编程的新手。我现在对于如何以异步和功能方式声明biz方法感到困惑,方法实现应该包含许多日志消息。作为一种不好的做法,我写这样的代码:
// trait
trait StoreService {
def create[Config]: Kleisli[Future, Config, Store]
}
// and the interpreter
trait StoreServiceInterpreter extends StoreService {
def create[Config]: Kleisli[Future, Config, Store] = Kleisli {cfg =>
// some implementation ...
log.info("bla bla bla ...")
// some implementation ...
// return a store
Store(...)
}
}
它很糟糕,导致实现带有副作用,记录到某个地方。所以,我改变方法声明如下:
// trait
trait StoreService {
def create[Config]: Kleisli[Future, Config, Writer[Vector[String], Store]]
}
// and the interpreter
trait StoreServiceInterpreter extends StoreService {
def create[Config]: Kleisli[Future, Config, Writer[Vector[String], Store]] = Kleisli {cfg =>
// some implementation ...
// log.info("bla bla bla ...")
// some implementation ...
// return a store
Writer(Vector("bla bla bla...", Store(...))
}
}
使用Writer,副作用被消除,但代码不清楚:
Writer[Vector[String], Store]
的噪音比Store
更多,有没有办法避免样板代码并保持无副作用?log
不是临时的!我应该构建一个String向量来保存消息,使用:+
或++
操作来添加日志。我认为它不是临时日志记录,就像在任何地方写log.info(...)
一样。答案 0 :(得分:1)
为方便起见,我认识的大多数Scala开发人员都倾向于将日志记录视为“非副作用”。但是,如果你真的想跟踪它们,你可能想看看“免费monad”概念。更多的信息: general description,example with logging。
我的粗略解释是“让我们将我们的程序建模为一些AST并解释它”。因此,在AST中,您定义了“日志记录”的概念,而不是实现,后来在解释中。这种方法允许您密切关注日志记录并更改操作(从写入/ dev / null到异步发布到外部服务),而不会影响代码的“业务”部分。