首页 > 解决方案 > 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函数需要一个 type 的参数Decorator,这println()显然不是。

另外我使用println(_),但是当我尝试传递这样的命名参数时,println(x)我得到一个错误。

标签: scaladecorator

解决方案


我是否理解正确,那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

为什么这里不需要声明返回类型?

正在声明返回类型(见上文)。

info一般来说,Scala 非常擅长推断类型,因此如果它可以从其他已知类型派生,您实际上不需要声明类型,但是

a) 良好的做​​法是声明非显而易见的类型,尤其是在公共值上。这可用作文档,加快编译速度并避免错误(如果推断的类型不是您想要的,它有助于跟踪问题)

b)在您的情况下,这也是让编译器知道logger这里应该有什么类型的最直接的方法。否则,您将不得不在其他地方声明。

为什么我可以println(_)传到uppercase?大写函数需要类型的参数Decorator,这println()显然不是。

uppercase不需要 a Decoratoruppercase 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。


推荐阅读