类型类在scala中继承`.apply`在哪里?

时间:2016-02-03 07:37:17

标签: scala playframework

我正在看这段代码

def loginForm = Form(mapping("username" -> text, "password" -> text)
    (LoginRequest.apply)(LoginRequest.unapply))

case class LoginRequest(username:String, password:String)

以下是Play

中表单的源代码
def mapping[R, A1, A2](a1: (String, Mapping[A1]), 
                       a2: (String, Mapping[A2]))
                      (apply: Function2[A1, A2, R])
                      (unapply: Function1[R, Option[(A1, A2)]]): 
    Mapping[R] = {
        new ObjectMapping2(apply, unapply, a1, a2)
    }

我想找出什么

LoginRequest.apply

实际意味着什么

ObjectMapping2(LoginRequest.apply, LoginRequest.unapply, "username" -> text, "password" -> text)

DO

1 个答案:

答案 0 :(得分:2)

您的LoginRequestcase class,因此包含由编译器自动插入的方法applyunapply。 Play需要他们知道如何从映射中构造和解构域对象。如果您有一些自定义代码,则需要自定义应用/取消应用,但由于您正在使用案例类(这是正确的做法),您可以简单地传递其开箱即用的应用和取消应用函数。

所以,为了回答你的第一个问题,LoginRequest.apply是一个可用于每个案例类的apply函数的调用。

回答你的第二个问题,

ObjectMapping2(LoginRequest.apply, LoginRequest.unapply, "username" -> text, "password" -> text)` 

表示将从“username”和“password”字符串创建一个新的LoginRequest,方法是将它们传递给LoginRequest.apply,这是LoginRequest案例类的构造函数。它还说明使用LoginRequest解析LoginRequest.unapply,这将返回Option[(String, String)](每个参数都有一个字符串,在您的情况下是用户名和密码)。

编辑:

我在评论中得到了合理的警告,以便更加准确。因此,在定义案例类时,编译器将在其伴随对象中自动生成apply()unapply()。您始终可以在您定义的任何类的任何伴随对象中包含这些方法。在这种情况下,编译器会为您完成。方法apply()在某种意义上是“特殊的”,它允许特殊的语法糖:而不是调用Something.apply(),它也可以简单地调用Something()

请注意,apply()unapply()不会被覆盖或实施;你(或者在这种情况下是编译器)只是从头开始定义它们就像任何其他自定义方法一样。但它是Scala编译器中允许语法糖的“技巧”。因此,如果您在MyClass的伴随对象中定义方法apply(),您当然可以按照MyClass.apply(whatever)的常规方式调用它,也可以MyClass(whatever)(这是技巧部分) 。

即使您有时不了解它,也会一直使用它 - 例如,编译器List(1, 2, 3)实际上将List.apply(1, 2, 3)置于List.apply()之内。这个技巧允许程序员编写更漂亮,更易读的代码(copy很难看,不是吗?)

与此特定问题无关,但我也要提一下 - 编译器还会为案例类添加一些其他方法:toStringequalshashCodeapply 。与unapplyapply不同,这些方法会添加到中(因此不会调用unapplyclass ViewController: UIViewController { @IBOutlet weak var marqueeLabel: MarqueeLabel! override func viewDidLoad() { super.viewDidLoad() self.marqueeLabel.tag = 101 self.marqueeLabel.type = .Continuous self.marqueeLabel.speed = .Duration(5) self.marqueeLabel.animationCurve = .EaseInOut self.marqueeLabel.fadeLength = 10.0 self.marqueeLabel.leadingBuffer = 30.0 self.marqueeLabel.trailingBuffer = 20.0 self.marqueeLabel.restartLabel() } } 等伴随对象,需要在case类的实例上调用。)