如何传递类结构(为了模式匹配)&模板作为方法参数

时间:2017-06-21 17:16:11

标签: scala class types playframework parameter-passing

行。所以我在我的控制器中有两个动作(使用 Play 2.5 & Scala 2.11.11 )。两者都向不同的外部API发出调用请求,并遵循相同的模式:

  def getSunResponse(lat: Double, lng: Double) = Action.async { request =>

    sw.makeServiceCall(lat,lng).map { response =>

      response match {
        case JsSuccess(r: SunInfo, path: JsPath) => Ok(views.html.temp1(r))
        case e: JsError => Ok(s"Errors: ${JsError.toJson(e).toString()}")
      }

    }
  }

.. ..和

  def getMoonResponse(lat: Double, lng: Double) = Action.async { request =>

    sw.makeServiceCall(lat,lng).map { response =>

      response match {
        case JsSuccess(r: MoonInfo, path: JsPath) => Ok(views.html.temp2(r))
        case e: JsError => Ok(s"Errors: ${JsError.toJson(e).toString()}")
      }

    }
  }

因为他们之间只有两个不同之处; 类模式匹配SunInfo& MoonInfo案例类在另一个文件中引用)和成功回复传递到views.html.temp1&的模板views.html.temp2 - 我宁愿消除不必要的重复,并在新的方法的参数中传递这些值,这取代了对这两者的需求。

所以要澄清我希望传递一个和一个模板(它可以接受成功的结果作为参数)。目前,我在理解函数签名中将传递的类型以及如何在方法体中引用它们时遇到一些困难。我在函数签名c: Class[_]中尝试classOf[c]作为参数,但当然它并不工作,因为它引用了对象而不是阶级结构。

目前非常欢迎有关如何传递这两个参数的任何指导。非常感谢!

2 个答案:

答案 0 :(得分:0)

如果我没有回答你的问题,我会道歉...我不知道Play,所以我不清楚需要什么样的请求和响应...但是当你要求“一种新的方法来代替需求时对于这两个“......我想到这样的事情......

trait CelestialBodyInfo
class SunInfo extends CelestialBodyInfo
class MoonInfo extends CelestialBodyInfo


def getResponse[T <: CelestialBodyInfo](lat: Double, lng: Double) = Action.async { request =>

  sw.makeServiceCall(lat,lng).map { response =>

    response match {
      case JsSuccess(r: T, path: JsPath) => r match {
        case s: SunInfo  => Ok(views.html.temp1(s))
        case m: MoonInfo => Ok(views.html.temp2(m))
      }
      case e: JsError => Ok(s"Errors: ${JsError.toJson(e).toString()}")
    }

  }
}

现在您可以将其称为......

getResponse[SunInfo](lat, lon)
getResponse[MoonInfo](lat, lon)

或者如果您不需要知道何时调用该函数,并且该请求会自动得到正确的响应...这样的事情?

def getResponse(lat: Double, lng: Double) = Action.async { request =>

  sw.makeServiceCall(lat,lng).map { response =>

    response match {
      case JsSuccess(r: CelestialBodyInfo, path: JsPath) => r match {
        case s: SunInfo  => Ok(views.html.temp1(s))
        case m: MoonInfo => Ok(views.html.temp2(m))
      }
      case e: JsError => Ok(s"Errors: ${JsError.toJson(e).toString()}")
    }

  }
}

编辑 - 回复评论

可能是其他事情发生在我不知道的播放中...但是在一般情况下,该错误消息将意味着SunInfo不是CelestialBodyInfo的子类型...它需要是基于类型T的类型边界。

创建相同错误消息的示例

trait A {
  def x: Int
}

class B(val x: Int) extends A // class B is subtype of A 
class C(val x: Int)           // class C is NOT a subtype of A 

// f requires an arg that is a subtype of A 
def f[T <: A](t: T) = t.x


f[B](new B(5))  // Int = 5 
f[C](new C(5))  // error: type arguments [C] do not conform to method f's type parameter bounds [T <: A]

所以,当我看到这个错误时,我的猜测是SunInfo不是CelestialBodyInfo的子类型,但是很难说还有什么可能会发生。

答案 1 :(得分:0)

试试这个:

def getSunOrMoonResponse(sunOrMoon: String,lat: Double,lng: Double) = 
  Action.async{ request =>
      sunOrMoon match {
        case "sun" => getResponse[SunInfo](new SunSW,lat,lng)(r => views.html.temp1(r))
        case "moon" => getResponse[MoonInfo](new MoonSW,lat,lng)(r => views.html.temp2(r))
      }
  }

protected def getResponse[T](sw: SW[T],lat: Double,lng: Double)(template: T => HtmlFormat.Appendable): Future[Result] = {
  sw.makeServiceCall(lat,lng).map{
    case JsSuccess(r: T,path) => Ok(template(r))
    case e: JsError => Ok(s"Errors: ${JsError.toJson(e).toString()}")
  }
}

trait SW[+T] {
  def makeServiceCall(lat: Double,lng: Double): Future[JsResult[T]]
}

class SunSW extends SW[SunInfo] {
  override def makeServiceCall(lat: Double, lng: Double):Future[JsResult[SunInfo]] = ???
}
class MoonSW extends SW[MoonInfo] {
  override def makeServiceCall(lat: Double, lng: Double): Future[JsResult[MoonInfo]] = ???
}

这里我假设获得SunInfo的sw和获得MoonInfo的sw遵循相同的接口。