Scala密封特质 - 复制枚举`withName`方法

4

我正在尝试将一个Enumeration重构为一个带具体类的密封特质,因为我需要在其中打包更多的功能。使用密封特质,我想要类似于EnumerationwithName(String)方法的功能。我已经编写了下面的代码来实现这一点,并寻求反馈:

sealed trait Foo {
  def name: String
}

object Foo {
  case object FooA extends Foo {
    override val name: String = "a"
  }

  case object FooB extends Foo {
    override val name: String = "b"
  }

  val values = Seq(FooA, FooB)

  def withName(name: String): Option[Foo] = {
    values.find(value => value.name.equals(name))
  }
}

接着,我可以使用withName(String)方法作为Option获取类型为Foo的相应具体对象:

val testFooAName = "a"
val testFooA = Foo.withName(testFooAName) // Will yield Some(FooA)

testFooA match {
    case Some(Foo.FooA) => println("Matched Foo.FooA!")
    case Some(Foo.FooB) => print("Matched Foo.FooB!")
}

val testFooNoneName = "none"
val testFooNone = Foo.withName(testFooNoneName) // Will yield None

Output:
Matched Foo.FooA!

这种方法正确吗?


1
仅有两个元素,但还是需要进行O(n)查找而不是O(1)查找……为withName方法设置一个私有的Map。此外,这似乎可以属于Code Review Stack Exchange。 - Andrey Tyukin
但是你仍然需要执行 values.find(_.name == name)。我们需要一组字符串来直接进行比较。 - Nagarjuna Pamu
1
你可以查看 https://github.com/lloydmeta/enumeratum - cchantep
1
Map 是一种 O(1) 查找的选择,但既然该 Map 已经是私有的,你也可以通过 name match {...} 并返回其中一个对象来避免额外的空间开销。 - aiguy
2个回答

2

是的,看起来很好。

小简化:使用地图进行快速查找。

val values = Seq(FooA, FooB)
val fastLookup = values.map(v => v.name -> v).toMap

def withName(name: String): Option[Foo] = fastLookup.get(name)

0

有一个方便的库由beachape提供,可以用来为您的sealed trait提供一些枚举功能。

您需要在sbt中包含的软件包是:

"com.beachape" %% "enumeratum" % "1.5.15"

然后像这样使用Enum扩展您的对象:

import enumeratum._

sealed trait Foo

object Foo extends Enum[Foo] {
  case object FooA extends Foo 
  case object FooB extends Foo 
}

你可以使用withName函数(以及其他函数)来获取你想要的密封特质:
Foo.withName("FooA")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接