首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >隐式对象内联工作,但在导入时不起作用。

隐式对象内联工作,但在导入时不起作用。
EN

Stack Overflow用户
提问于 2020-08-06 18:14:00
回答 1查看 89关注 0票数 1

我使用avro4s来帮助avro序列化和反序列化。

我有一个包含Timestamp的case类,在将记录发布到Kafka之前,需要将这些Timestamp转换成格式良好的字符串;默认的编码器是将Timestamps转换为Longs。我读到需要编写解码器和编码器(从avro4s自述)。

这是我的案例课:

代码语言:javascript
复制
case class MembershipRecordEvent(id: String,
                                 userHandle: String,
                                 planId: String,
                                 teamId: Option[String] = None,
                                 note: Option[String] = None,
                                 startDate: Timestamp,
                                 endDate: Option[Timestamp] = None,
                                 eventName: Option[String] = None,
                                 eventDate: Timestamp)

我写了以下编码器:

Test.scala

代码语言:javascript
复制
def test() = {
implicit object MembershipRecordEventEncoder extends Encoder[MembershipRecordEvent] {
  override def encode(t: MembershipRecordEvent, schema: Schema) = {
    val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
    val record = new GenericData.Record(schema)
    record.put("id", t.id)
    record.put("userHandle", t.userHandle)
    record.put("teamId", t.teamId.orNull)
    record.put("note", t.note.orNull)
    record.put("startDate", dateFormat.format(t.startDate))
    record.put("endDate", if(t.endDate.isDefined) dateFormat.format(t.endDate.get) else null)
    record.put("eventName", t.eventName.orNull)
    record.put("eventDate", dateFormat.format(t.eventDate))
    record
    }
  }

val recordInAvro2 = Encoder[MembershipRecordEvent].encode(testRecord, AvroSchema[MembershipRecordEvent]).asInstanceOf[GenericRecord]
    println(recordInAvro2)
}

如果我按照上面的方式声明我的implicit object,它会创建我正在寻找的GenericRecord。我试图将implicit object抽象到一个文件中,并将其封装在一个对象中,然后使用import Implicits._来使用我的自定义编码器。

Implicits.scala

代码语言:javascript
复制
object Implicits {
implicit object MembershipRecordEventEncoder extends Encoder[MembershipRecordEvent] {
  override def encode(t: MembershipRecordEvent, schema: Schema) = {
    val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
    val record = new GenericData.Record(schema)
    record.put("id", t.id)
    record.put("userHandle", t.userHandle)
    record.put("teamId", t.teamId.orNull)
    record.put("note", t.note.orNull)
    record.put("startDate", dateFormat.format(t.startDate))
    record.put("endDate", if(t.endDate.isDefined) dateFormat.format(t.endDate.get) else null)
    record.put("eventName", t.eventName.orNull)
    record.put("eventDate", dateFormat.format(t.eventDate))
    record
    }
  }
}

Test.scala

代码语言:javascript
复制
import Implicits._
val recordInAvro2 = Encoder[MembershipRecordEvent].encode(testRecord, AvroSchema[MembershipRecordEvent]).asInstanceOf[GenericRecord]
    println(recordInAvro2)

它不能使用我的编码器(没有击中我的断点)。我已经尝试了无数的事情,试图看看为什么它失败了。

如何正确导入隐式对象?

是否有更简单的解决方案可以将我的case classTimestamp编码成Strings,而无需为整个case class编写编码器?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-06 19:54:09

TL;DR

正如上面的注释中所建议的那样,您可以将其放置在伴生对象中。

较长的版本:

您可能有另一个编码器,它用于代替您在Implicits中定义的编码器。

我会引用SCALA在哪里寻找IMPLICITS?的一些短语

当需要某个名称的值时,将搜索具有该名称的值。类似地,当需要某种类型的隐式值时,将搜索具有该类型的值。 可以用其“简单”名称引用的任何此类值,而无需使用虚线语法从另一个值中选择,都是合格的隐式值。可能有多个这样的值,因为它们有不同的名称。 在这种情况下,过载解析被用来选择其中之一。重载解析算法与为给定名称选择引用时使用的算法相同,当作用域中有多个术语具有该名称时。例如,println是重载的,每个重载都采用不同的参数类型。对println的调用需要选择正确的重载方法。 在隐式搜索中,重载解析在具有相同所需类型的多个值中选择一个值。通常,这需要选择一个较窄的类型或在子类中定义的相对于其他合格值的值。 必须使用其简单名称访问该值的规则意味着适用用于名称绑定的常规规则。 总之,x的定义隐藏在一个封闭作用域中的定义。但是,本地进口也可以引入x的绑定。导入的符号不能覆盖封闭作用域中的同名定义。类似地,通配符导入不能覆盖特定名称的导入,当前包中从其他源文件中可见的名称不能覆盖导入或本地定义。 这是确定x在给定上下文中的含义的正常规则,也决定了哪个值x可以通过其简单名称访问,并且可以作为隐式。 这意味着,通过用同名的术语对其进行阴影,可以禁用范围中的隐式。

现在,我将陈述配套的对象逻辑:

隐式语法可以通过利用“隐式范围”来避免进口税,这当然是一种“罪恶税”,这取决于词法范围中隐式而不是导入的类型。 当需要类型T的隐式时,隐范围包括伴随对象T:当需要FT时,隐范围既包括F的伙伴,也包括类型参数的同伴,例如,对象C用于FC。 此外,隐式范围还包括F和C的基类的伙伴,包括包对象,如p表示p.F。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63289467

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档