Scala中的装饰者模式
我在 Scala 中有以下代码。我有几个关于功能和语法的问题。
type Logger = String => Unit
type Decorator = Logger => Logger
val uppercase: Decorator =
logger =>
(msg: String) => logger(msg.toUpperCase)
val info: Decorator =
logger =>
(msg:String) => logger("info " + msg)
我理解正确吗,那Decorator是ìnfo函数的输入?
为什么这里不需要声明返回类型?
然后我使用这样的代码:
val prefixUppercase = info(uppercase(println(_)))
为什么我可以通过println(_)对uppercase?
该uppercase函数需要一个类型为 的参数Decorator,这println()显然不是。
另外,我使用println(_),但是当我尝试传递这样的命名参数时,println(x)我收到一个错误。
回答
我理解正确吗,那
Decorator是ìnfo函数的输入?
val info: Decorator =
logger =>
(msg:String) => logger("info " + msg)
不,Decorator是类型的info。
info被声明为一个函数 from Loggerto Logger(Decorator扩展到)。
val info: Decorator = // info is a Decorator
// i.e. a function Logger => Logger
logger => // so this makes logger a Logger
// (the input for the Decorator)
// what follows is the output of the Decorator
// i.e. another Logger
// i.e. a function String => Unit
(msg:String) => // so this is that String input to the
// resulting (decorated) Logger
logger("info " + msg) // and this is what our decorator does
// to the String to be logged:
// we prefix it with "info "
// and give it to the underlying logger
为什么这里不需要声明返回类型?
正在声明返回类型(见上文)。
一般来说,Scala 非常擅长推断类型,因此您实际上不需要声明类型info是否可以从其他已知类型派生,但是
a) 声明非显而易见的类型是一种很好的做法,尤其是在公共值上。这可以作为文档,加速编译并可以避免错误(如果推断的类型不是你想要的,它有助于追踪问题)
b) 在你的情况下,这也是让编译器知道logger这里应该有什么类型的最直接的方法。否则,您将不得不在其他地方声明。
为什么我可以通过
println(_)对uppercase?大写函数需要一个类型为 的参数Decorator,这println()显然不是。
uppercase不需要 a Decorator,uppercase 是a Decorator,这意味着它是一个接受 aLogger并返回 a的函数Logger。
所以它需要 a Logger,这是一个接受 aString并且不返回任何内容的函数。println是这样一个函数,因此您可以将其传递给uppercase(作为其Logger输入参数)。
我尝试传递这样的命名参数
println(x),但出现错误。
什么是x在这种情况下?
您需要创建一个Logger,这意味着一个接受 String 并且不返回任何特殊内容的函数。
x => println(x) 会做。
println(_) 是同一件事的简写,并且会做。
println(somethingElse)或者println(123)不再接受 String 的函数(它们不再接受任何参数)所以那些不是Loggers。