17

ケースクラスのインスタンスとして文字列を読み取りたいのですが。たとえば、関数の名前が「read」の場合、次のようになります。

case class Person(name: String, age: Int)
val personString: String = "Person(Bob,42)"
val person: Person = read(personString)

これは、Haskellの読み取り型クラスと同じ動作です。

4

6 に答える 6

14

dflemstr answered more towards setting up the actual read method- I'll answer more for the actual parsing method.

My approach has two objects that can be used in scala's pattern matching blocks. AsInt lets you match against strings that represent Ints, and PersonString is the actual implementation for Person deserialization.

object AsInt {
  def unapply(s: String) = try{ Some(s.toInt) } catch {
    case e: NumberFormatException => None
  }
}

val PersonRegex = "Person\\((.*),(\\d+)\\)".r

object PersonString {
  def unapply(str: String): Option[Person] = str match {
    case PersonRegex(name, AsInt(age)) => Some(Person(name, age))
    case _ => None
  }
}

The magic is in the unapply method, which scala has syntax sugar for. So using the PersonString object, you could do

val person = PersonString.unapply("Person(Bob,42)")
//  person will be Some(Person("Bob", 42))

or you could use a pattern matching block to do stuff with the person:

"Person(Bob,42)" match {
  case PersonString(person) => println(person.name + " " + person.age)
  case _ => println("Didn't get a person")
}
于 2012-05-29T19:10:55.340 に答える
9

Scalaには型クラスがありません。この場合、特性はオブジェクトのメソッドのみを表現するため、継承された特性を使用して型クラスをシミュレートすることもできません。つまり、クラスが「所有」する必要があります。 「文字列を唯一の引数として取るコンストラクター」(これは、OOP言語で「読み取り」と呼ばれる可能性があるもの)の定義を特性に入れることはできません。

代わりに、型クラスを自分でシミュレートする必要があります。これはそのように行われます(コメント内の同等のHaskellコード):

// class Read a where read :: String -> a
trait Read[A] { def read(s: String): A }

// instance Read Person where read = ... parser for Person ...
implicit object ReadPerson extends Read[Person] {
  def read(s: String): Person = ... parser for Person ...
}

次に、型クラスに依存するメソッドがある場合は、それを暗黙のコンテキストとして指定する必要があります。

// readList :: Read a => [String] -> [a]
// readList ss = map read ss
def readList[A: Read] (ss: List[String]): List[A] = {
  val r = implicitly[Read[A]] // Get the class instance of Read for type A
  ss.map(r.read _)
}

ユーザーは、使いやすさのために、おそらく次のようなポリモーフィックメソッドを望んでいます。

object read {
  def apply[A: Read](s: String): A = implicitly[Read[A]].read(s)
}

次に、次のように書くことができます。

val person: Person = read[Person]("Person(Bob,42)")

特に、この型クラスの標準的な実装については知りません。

また、免責事項:私はScalaコンパイラーを持っておらず、この言語を何年も使用していないため、このコードがコンパイルされることを保証できません。

于 2012-05-29T18:53:11.693 に答える
8

Starting Scala 2.13, it's possible to pattern match a Strings by unapplying a string interpolator:

// case class Person(name: String, age: Int)
"Person(Bob,42)" match { case s"Person($name,$age)" => Person(name, age.toInt) }
// Person("Bob", 42)

Note that you can also use regexes within the extractor.

Which in this case, helps for instance to match on "Person(Bob, 42)" (age with a leading space) and to force age to be an integer:

val Age = "[ ?*](\\d+)".r

"Person(Bob, 42)" match {
  case s"Person($name,${Age(age)})" => Some(Person(name, age.toInt))
  case _ => None
}
// Person = Some(Person(Bob,42))
于 2019-04-06T19:44:19.720 に答える
6

The answers on this question are somewhat outdated. Scala has picked up some new features, notably typeclasses and macros, to make this more easily possible.

Using the Scala Pickling library, you can serialize/deserialize arbitrary classes to and from various serialization formats:

import scala.pickling._
import json._

case class Person(name: String, age: Int)
val person1 = Person("Bob", 42)
val str = person1.pickle.value // { tpe: "Person", name: "Bob", age: 42 }
val person2 = JSONPickle(str).unpickle[Person]

assert(person1 == person2) // Works!

The serializers/deserializers are automatically generated at compile time, so no reflection! If you need to parse case classes using a specific format (such as the case class toString format), you can extend this system with your own formats.

于 2014-05-12T13:41:14.457 に答える
1

The uPickle library offers a solution for this problem.

于 2015-01-27T14:57:02.473 に答える
-1

Scala uses Java's serialization stuff, with no String representation.

于 2012-05-29T21:16:50.847 に答える