在Scala中返回2个以上不同变量类型值的最佳方法是什么?

时间:2015-11-25 02:11:34

标签: scala

已经过去了因为我已经开始研究scala了,我想知道当我创建一个需要返回多个数据的方法时哪种变量类型最好。

让我们说如果我必须制定一种获取用户信息的方法,并且可以从很多地方拨打电话。

  def getUserParam(userId: String):Map[String,Any] = {
    //do something
    Map(
      "isExist" -> true,
      "userDataA" -> "String",
      "userDataB" -> 1 // int
    )
  }

在这种情况下,结果类型为Map[String,Any],并且由于每个参数都会被识别为Any,因此您无法将该值传递给需要特殊处理的其他方法。

def doSomething(foo: String){}
val foo = getUserParam("bar")
doSomething(foo("userDataA")) // type mismatch error

如果我使用Tuple,我可以避免该错误,但我不认为很容易猜出每个索引编号包含的内容。

当然可以选择使用Case Class但是一旦我使用case类作为返回类型,我需要在我调用方法的地方导入case类。

我想问的是什么是使方法返回2个以上不同变量类型值的最佳方法。

2 个答案:

答案 0 :(得分:2)

以下是三个选项。即使你可能喜欢第三种选择(使用匿名类),它实际上是我最不喜欢的。如您所见,它需要您启用反射调用(否则会抛出编译警告)。 Scala将使用反射来实现这一点并不是那么好。

就个人而言,如果只有2个值我使用元组。如果有两个以上,我会使用一个case类,因为它大大提高了代码的可读性。匿名类选项我知道它存在了一段时间,但我从来没有用过我的代码。

import java.util.Date

def returnTwoUsingTuple: (Date, String) = {
    val date = new Date()
    val str = "Hello world"
    (date,str)
}

val tupleVer = returnTwoUsingTuple
println(tupleVer._1)
println(tupleVer._2)


case class Reply(date: Date, str: String)
def returnTwoUsingCaseClass: Reply = {
    val date = new Date()
    val str = "Hello world"
    Reply(date,str)
}

val caseClassVer = returnTwoUsingCaseClass
println(caseClassVer.date)
println(caseClassVer.str)


import scala.language.reflectiveCalls
def returnTwoUsingAnonymousClass = {
    val date = new Date()
    val str = "Hello world"
    new {
        val getDate = date
        val getStr = str
    }
}

val anonClassVer = returnTwoUsingAnonymousClass
println(anonClassVer.getDate)
println(anonClassVer.getStr)

答案 1 :(得分:1)

Sinse你的逻辑Map[String,Any]更像是,因为我拥有的每个键都是而不是每个键我都有... 更有效在这种情况下,使用Either或更有效 - scalaz.\/

scalaz。\ /

import scalaz._
import scalaz.syntax.either._

def getUserParam(userId: String): Map[String, String \/ Int \/ Boolean] = {
  //do something
  Map(
    "isExist" -> true.right,
    "userDataA" -> "String".left.left,
    "userDataB" -> 1.right.left
  )
}

String \/ Int \/ Boolean(String \/ Int) \/ Boolean

保持联系

现在你有了

def doSomething(foo: String){}

不幸的是,这是最复杂的情​​况,例如你有

def doSomethingB(foo: Boolean){}

你可能只是

foo("userDataA").foreach(doSomethingB)

因为 正确 值被视为 正确 所以String 离开你可以写

foo("userdata").swap.foreach(_.swap.foreach(doSomething))

已关闭的家庭

或者您可以为大量替代品制作自己的简单类型,例如

sealed trait Either3[+A, +B, +C] {
  def ifFirst[T](action: A => T): Option[T] = None
  def ifSecond[T](action: B => T): Option[T] = None
  def ifThird[T](action: C => T): Option[T] = None
}

case class First[A](x: A) extends Either3[A, Nothing, Nothing] {
  override def ifFirst[T](action: A => T): Option[T] = Some(action(x))
}

case class Second[A](x: A) extends Either3[Nothing, A, Nothing] {
  override def ifSecond[T](action: A => T): Option[T] = Some(action(x))
}

case class Third[A](x: A) extends Either3[Nothing, Nothing, A] {
  override def ifThird[T](action: A => T): Option[T] = Some(action(x))
}

现在有了

def getUserParam3(userId: String): Map[String, Either3[Boolean, String, Int]] = {
  //do something
  Map(
    "isExist" -> First(true),
    "userDataA" -> Second("String"),
    "userDataB" -> Third(1)
  )
}

val foo3 = getUserParam3("bar")

您可以将您的值用作

foo3("userdata").ifSecond(doSomething)