gpt4 book ai didi

scala - 将分隔字符串反序列化为案例类的惯用 Scala 方法

转载 作者:行者123 更新时间:2023-12-02 01:54:38 26 4
gpt4 key购买 nike

假设我正在处理一个简单的以冒号分隔的文本协议(protocol),看起来像这样:

Event:005003:information:2013 12 06 12 37 55:n3.swmml20861:1:Full client swmml20861 registered [entry=280 PID=20864 queue=0x4ca9001b]
RSET:m3node:AUTRS:1-1-24:A:0:LOADSHARE:INHIBITED:0
M3UA_IP_LINK:m3node:AUT001LKSET1:AUT001LK1:r
OPC:m3node:1-10-2(P):A7:NAT0
....

我想将每一行反序列化为案例类的实例,但要以类型安全的方式进行。我的第一次尝试使用类型类为我可能遇到的每种可能类型定义“读取”方法,此外还使用案例类上的“元组”方法来取回可应用于参数元组的函数,例如以下内容:

case class Foo(a: String, b: Integer)

trait Reader[T] {
def read(s: String): T
}

object Reader {
implicit object StringParser extends Reader[String] { def read(s: String): String = s }
implicit object IntParser extends Reader[Integer] { def read(s: String): Integer = s.toInt }
}

def create[A1, A2, Ret](fs: Seq[String], f: ((A1, A2)) => Ret)(implicit A1Reader: Reader[A1], A2Reader: Reader[A2]): Ret = {
f((A1Reader.read(fs(0)), A2Reader.read(fs(1))))
}

create(Seq("foo", "42"), Foo.tupled) // gives me a Foo("foo", 42)

但问题是我需要为每个元组和函数元数定义创建方法,因此这意味着最多 22 个版本的创建。此外,这不会处理验证或接收损坏的数据。

最佳答案

因为有一个 Shapeless 标签,一个可能的解决方案是使用它,但我不是专家,我想可以做得更好:

首先,关于缺少验证,如果您不关心错误消息,您应该简单地阅读 return Try 或 scalaz.Validation 或 just option。

然后关于样板,你可以尝试使用HList。这样你就不需要去寻找所有的东西。

import scala.util._
import shapeless._

trait Reader[+A] { self =>
def read(s: String) : Try[A]
def map[B](f: A => B): Reader[B] = new Reader[B] {
def read(s: String) = self.read(s).map(f)
}
}

object Reader {
// convenience
def apply[A: Reader] : Reader[A] = implicitly[Reader[A]]
def read[A: Reader](s: String): Try[A] = implicitly[Reader[A]].read(s)

// base types
implicit object StringReader extends Reader[String] {
def read(s: String) = Success(s)
}
implicit object IntReader extends Reader[Int] {
def read(s: String) = Try {s.toInt}
}

// HLists, parts separated by ":"
implicit object HNilReader extends Reader[HNil] {
def read(s: String) =
if (s.isEmpty()) Success(HNil)
else Failure(new Exception("Expect empty"))
}
implicit def HListReader[A : Reader, H <: HList : Reader] : Reader[A :: H]
= new Reader[A :: H] {
def read(s: String) = {
val (before, colonAndBeyond) = s.span(_ != ':')
val after = if (colonAndBeyond.isEmpty()) "" else colonAndBeyond.tail
for {
a <- Reader.read[A](before)
b <- Reader.read[H](after)
} yield a :: b
}
}

}

鉴于此,您的 Foo 阅读器相当短:

case class Foo(a: Int, s: String) 

object Foo {
implicit val FooReader : Reader[Foo] =
Reader[Int :: String :: HNil].map(Generic[Foo].from _)
}

有效:

println(Reader.read[Foo]("12:text"))
Success(Foo(12,text))

关于scala - 将分隔字符串反序列化为案例类的惯用 Scala 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20939716/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com