You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用scalapb在proto中定义Option[FiniteDuration]类型

proto3 + ScalaPB 实现FiniteDuration及Option[FiniteDuration]映射方案

1. 编写proto定义

使用谷歌官方的google.protobuf.Duration标准类型作为中间载体,同时开启proto3的optional语法实现可选字段:

syntax = "proto3";

// 导入依赖
import "google/protobuf/duration.proto";
import "scalapb/scalapb.proto";

message Message {
  int32 id = 1;
  // optional关键字默认映射为Scala Option类型,同时指定自定义映射类型
  optional google.protobuf.Duration interval = 2 [
    (scalapb.field).type = "scala.concurrent.duration.FiniteDuration"
  ];
}

2. 定义FiniteDuration类型转换器

自定义TypeMapper实现google.protobuf.Duration和Scala原生FiniteDuration的双向转换:

import com.google.protobuf.duration.Duration
import scala.concurrent.duration.{FiniteDuration, SECONDS, NANOSECONDS}

object ProtoTypeMappers {
  implicit val finiteDurationMapper: scalapb.TypeMapper[Duration, FiniteDuration] = 
    scalapb.TypeMapper[Duration, FiniteDuration](
      // proto转Scala
      protoDur => FiniteDuration(protoDur.seconds, SECONDS) + FiniteDuration(protoDur.nanos, NANOSECONDS)
    )(
      // Scala转proto
      scalaDur => Duration(
        seconds = scalaDur.toSeconds,
        nanos = (scalaDur.toNanos % 1000_000_000).toInt
      )
    )
}

3. 配置ScalaPB编译参数

在build.sbt中添加配置,让生成的代码自动导入你定义的转换器隐式值:

Compile / PB.targets += scalapb.gen(
  // 替换为你实际的ProtoTypeMappers所在包路径
  scalapbImports = Seq("your.project.package.ProtoTypeMappers._")
) -> (Compile / sourceManaged).value / "scalapb"

效果验证

完成上述配置后,ScalaPB自动生成的样例类就和需求完全一致:

case class Message(id: Int, interval: Option[FiniteDuration])

注意事项

  • 需使用proto3 3.12及以上版本支持optional语法,若版本过低可将interval字段包裹在oneof中实现可选效果
  • 转换时注意纳秒精度处理,避免丢数
  • 转换器的包路径要和build.sbt中配置的导入路径一致,否则编译会报缺失TypeMapper的错误

内容的提问来源于stack exchange,提问作者coder25

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 01:54:00