Java 如何将类型映射到Scala中的值?
我认为在ScalaJava 如何将类型映射到Scala中的值?,java,scala,types,Java,Scala,Types,我认为在ScalaMap[Class[\up>中,您真正想要的是从Rank到Int的部分函数。与为域的所有元素定义的全部函数不同,部分函数只能为其中的一些元素定义 另外,如果您不介意另一个建议的话,抛出异常并不符合函数式编程的精神。我不会将函数式方法强加给您,因为Scala完全可以用于面向对象(类似Java)中方式。但我要建议它。它说-不要扔!我总是说扔就像完全撕裂了你程序的结构。它撕开墙壁,说“好吧,现在我走捷径”。这几乎就像goto语句。如果你决定使用异常,我敢肯定你可以修改我的示例来合并它
Map[Class[\up>中,您真正想要的是从Rank
到Int
的部分函数。与为域的所有元素定义的全部函数不同,部分函数只能为其中的一些元素定义
另外,如果您不介意另一个建议的话,抛出异常并不符合函数式编程的精神。我不会将函数式方法强加给您,因为Scala完全可以用于面向对象(类似Java)中方式。但我要建议它。它说-不要扔!我总是说扔就像完全撕裂了你程序的结构。它撕开墙壁,说“好吧,现在我走捷径”。这几乎就像goto语句。如果你决定使用异常,我敢肯定你可以修改我的示例来合并它们
我的建议是,不要抛出,而是明确指出您的函数最终可能会导致错误值。您可以使用或者[MyErrorType,MyValueType]
轻松地执行此操作。这样,您最终返回的值需要是左(instanceOfMyErrorType)
或者右(instanceOfMyValueType)
。之后,在一些需要处理错误的代码中,您可以随时检查您手中是否有右
或左
,并相应地采取行动(例如,如果左记录错误并返回400 HTTP响应或其他响应)
代码如下:
sealed trait Rank
case object Ace extends Rank
case object King extends Rank
case object Queen extends Rank
case object Jack extends Rank
case object Ten extends Rank
// ...
final case class Error(msg: String)
val exampleMapping: PartialFunction[Rank, Int] =
(rank: Rank) => rank match {
case Ace => 11
case King => 10
case Queen => 10
case Jack => 10
// No Ten!
}
def valuations(rank: Rank, f: PartialFunction[Rank, Int]): Either[Error, Int] =
f.andThen(rank => Right(rank)).applyOrElse(
rank,
(v: Rank) => Left(Error(s"No such element: $v"))
)
val a = valuations(King, exampleMapping) // Right(10)
val b = valuations(Ten, exampleMapping) // Left(Error(No such element: Ten))
上面代码中最有趣的部分是估价方法
- 给我一个
rank:rank
和一个从rank
到Int
的部分函数,我将返回Int
或错误
- 我现在要做的是,我用一个函数组合提供的函数,该函数将该值转换为
右(该整数)
(或者,用数学术语,将后者与前者组合;f,然后g
表示g(f(x))
,而f组合g
表示f(x))
…我总是觉得使用在精神上更容易,然后
)
- 将上面定义的组合应用于
rank
参数,如果该函数没有为rank
定义结果,那么返回Left(error)
当然,您可以有许多不同的部分函数,其他用户可以定义自己的函数,等等。不过请注意两件事:
- 使用sealed trait意味着没有人可以扩展
Rank
。这对我来说是有意义的。但是,如果您希望以后不仅能够添加不同的映射,甚至能够添加新的Rank
s,那么就不要将trait密封起来
- 创建您的case类是因为它们不应该被扩展,通过将它们设置为最终类,若您试图定义一个总函数(而不是部分函数),编译器将向您发出警告,但由于意外地忽略了某个等级的
案例
,因此忘记了处理某些案例。对于案例对象,如果您也将它们标记为final也可以,但这不是强制性的,因为它们无论如何都不能扩展(它们只能有一个实例,就像Java中的singleton)
如果出于任何原因,您后来决定在映射未定义时不希望返回错误,而是希望使用一个默认映射,该映射具有所有列组的所有默认值(=它不是一个局部函数Rank=>Int
,而是一个总函数),那么这也很容易做到。尝试一下吧
最后请注意,Scala 3将有非常好的枚举,这是您在Java中熟悉的,而Scala 2缺少的。我认为@slouc answer很好(代数数据类型(ADT)/密封特征、错误值等),但您确实应该避免使用分部函数(除了某些方法,如List#collect
,它在未定义的输入上不会失败)并尽可能多地使用total函数。您可以将exampleMapping
转换为Rank=>选项[Int]
,但我认为您应该改用map
密封特征等级
对象秩{
//如果你想把这些放在窝里就看你了
case对象扩展秩
case-object-King扩展了等级
case对象扩展秩
case对象Jack扩展秩
案例对象10扩展等级
案例对象九扩展了等级
//...
}
val exampleMapping=Map(
排名.Ace->11,
等级:国王->10,
等级:女王->10,
排名:杰克->10,
排名10->10
)
def赋值(秩:秩,m:Map[rank,Int]):要么[Error,Int]=
m、 get(rank).toRight(新错误“无此类元素:$rank”))
如果您实际上不需要变量映射(或者如果映射在编译时已知,那么最好将它们实现为单独的列组类型),那么您应该只在中实现值(这不是更像枚举吗?)
密封抽象类秩(val-maybeValue:Option[Int])
对象秩{
案例对象Ace扩展等级(部分(11))
case object King扩展秩(一些(10))
case object Queen扩展秩(一些(10))
案例对象杰克扩展等级(一些(10))
案例对象十扩展等级(一些(10))
案例对象九扩展秩(无)
//...
}
def赋值(秩:秩):要么[Error,Int]=
rank.maybeValue.toRight(新错误“无此类元素:$rank”))
如果值不是可选的(如Java枚举…):
密封抽象类秩(val值:Int)
对象秩{
案例对象Ace扩展秩(11)
案例对象国王扩展等级(10)
案例对象扩展秩(10)
案例对象杰克扩展等级(10)
案例对象10扩展秩(10)
案例对象九扩展秩(9)
//...
}
//如果错误不是可选的,我们甚至不需要错误,而且这个方法现在有点毫无意义。。。
def估值(秩:秩):Int=rank.value
现在,对于多个等级类型,您可以使用子类型进行泛化(这会破坏您的ADT)(等等,我们甚至可以将Java子类化吗
class Valuations(val map: Map[Class[_ <: Rank], Int]) {
def valueOf(rank: Rank): Int = {
val key = rank.getClass
if (map.contains(key) map.get(key) else {
throw new NoSuchElementException("No match for " + rank.toString)
}
}
}
sealed trait Rank
case object Ace extends Rank
case object King extends Rank
case object Queen extends Rank
case object Jack extends Rank
case object Ten extends Rank
// ...
final case class Error(msg: String)
val exampleMapping: PartialFunction[Rank, Int] =
(rank: Rank) => rank match {
case Ace => 11
case King => 10
case Queen => 10
case Jack => 10
// No Ten!
}
def valuations(rank: Rank, f: PartialFunction[Rank, Int]): Either[Error, Int] =
f.andThen(rank => Right(rank)).applyOrElse(
rank,
(v: Rank) => Left(Error(s"No such element: $v"))
)
val a = valuations(King, exampleMapping) // Right(10)
val b = valuations(Ten, exampleMapping) // Left(Error(No such element: Ten))