我可以在scala中使用协方差传递不同的表单数据类型吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我可以在scala中使用协方差传递不同的表单数据类型吗?相关的知识,希望对你有一定的参考价值。

就像documentation for covariance说的那​​样:

对于某些类List [+ A],使A变量意味着对于两种类型A和B,其中A是B的子类型,则List [A]是List [B]的子类型

这也适用于Form(如scala形式)吗?我遇到了传递各种形式的问题。以下是我正在做的一个示例:

   abstract class SuperCovariance

   case class TestCovariance1(id: Option[Int], name: String, another: String) extends SuperCovariance

   case class TestCovariance2(id: Option[Int], differentName: String, other: String) extends SuperCovariance

   object Tc1Form {

     val form = Form(
       mapping(
         "_id" -> optional(number),
         "name" -> nonEmptyText,
         "another" -> nonEmptyText
       )(TestCovariance1.apply)(TestCovariance1.unapply)
     )

   }

   object Tc2Form {

     val form = Form(
       mapping(
         "_id" -> optional(number),
         "differentName" -> nonEmptyText,
         "other" -> nonEmptyText
       )(TestCovariance2.apply)(TestCovariance2.unapply)
     )

   }

如果其中一个表单可以作为方法中的参数传递,我认为我可以这样做:

     def acceptAnySubTypeOfSuperCovariance(myForm: Form[SuperCovariance])(implicit request: Request[AnyContent]): Result = {
       Ok(views.html.myTemplate(myForm))
     }

调用此方法并传递Form[TestCovariance1]类型会导致错误,这会导致我理解问题以及如何避免为SuperCovariance的每个子类型编写此类方法。欢迎任何帮助/启发!


为了澄清我想要能够做到这一点的理由 - 这是为了避免为每个表单编写重复的代码行。因此,如果我有多个表单,我宁愿在控制器中有一个方法来绑定请求中的数据,例如

   def updateDoc(collectionName: String, oId: Option[BSONObjectID]) = Action.async { implicit request: Request[AnyContent] =>

       MyModel.form.bindFromRequest.fold(
         errorForm => Future.successful(Ok(views.html.errorTemplate(errorForm, MyModel)),
         data => {

           val updatedDoc = ?? // map data to model here, e.g. TestCovariance1(None, data.name, data.another)

           // calls a method 
           updateMultipleFields[MyModel](collectionName, updatedDoc, oId).map(x =>
             Redirect(routes.DatabaseC.editIndex(collName, oId.get))
           )

         }
       )
   }

  // generic method to update fields in collection (Mongo database)
  def updateMultipleFields[T](collectionName: String, model: T, id: Option[BSONObjectID])(implicit writes: Writer[T]): Future[Result] = {

    val idSelector = Json.obj("_id" -> id)
    getCollection(collectionName).flatMap(collection =>
      collection.update(idSelector, Json.obj("$set" -> model)).map {
        lastError =>
          Created("fields updated")
      }
    )

  }

我认为MVC结构可以灵活地允许我以这样的方式设置数据处理,如果正确(并且安全地)完成的话;我可以通过创建新模型(表单和模型)来简单地添加数据。如果我不能;它不会阻止应用程序的功能,但似乎重复这些类似锅炉板的代码是Scala存在的原因之一。

答案

不,我不认为您提到的链接引用可以在您的示例中使用。为了工作,Form类本身应该在T Form[+T]中被声明为协变,他们不能这样做,因为它用于两个方向的转换。你仍然可以做你喜欢的事情

 def acceptAnySubTypeOfSuperCovariance[T:<SuperCovariance](myForm: Form[T])(implicit request: Request[AnyContent]): Result = 

但是这段代码让我很奇怪:你真的想通过Form[some subclass of SuperCovariance]吗?你的acceptAnySubTypeOfSuperCovariance真正做了什么你想要这样做?通常,从请求绑定数据并获取对象然后传递它更有意义。这将在不需要泛型的情况下工作。

以上是关于我可以在scala中使用协方差传递不同的表单数据类型吗?的主要内容,如果未能解决你的问题,请参考以下文章

Scala:如何获得矩阵的均值、方差和协方差?

表单的不同 POST 选项,然后传递数据

如何在Spring Boot控制器类中传递参数(app正在使用Spring Security)

Scala中的协方差

在struts 2中将可变数量的参数从表单传递到动作

Scala高阶