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

Scala 3.3 Akka HTTP/Actor类型不匹配错误求助

解决Scala 3.3 + Akka Actor/HTTP中的类型不匹配问题

问题背景

使用Scala 3.3结合Akka Actor构建Akka HTTP应用,在StarRegistry对象中创建恒星、行星、卫星时,希望将它们分别存储在Map[String, Set[HeavenlyBody]]的对应键下("stars"对应Set[CreateStar],"planets"对应Set[CreatePlanet],"moons"对应Set[CreateMoon]),通过starRoutes提供API实现创建和查询功能,但编译时出现类型不匹配错误:

Type Mismatch Error: D:\Studio\WORK\akka\AKKA-HTTP\scala-akka-http-interstellar-IoT\src\main\scala\com\example\StarRegistry.scala:
replyTo ! Stars(map.get("stars").toSeq)
Found:    Seq[Set[com.example.HeavenlyBody]]
Required: Seq[com.example.CreateStar]

Type Mismatch Error: D:\Studio\WORK\akka\AKKA-HTTP\scala-akka-http-interstellar-IoT\src\main\scala\com\example\StarRegistry.scala:199:45 
replyTo ! Planets(map.get("planets").toSeq)
Found:    Seq[Set[com.example.HeavenlyBody]]
Required: Seq[com.example.CreatePlanet]

Type Mismatch Error: D:\Studio\WORK\akka\AKKA-HTTP\scala-akka-http-interstellar-IoT\src\main\scala\com\example\StarRegistry.scala:213:41 
replyTo ! Moons(map.get("moons").toSeq)
Found:    Seq[com.example.HeavenlyBody]
Required: Seq[com.example.CreateMoon]

错误原因

  1. 类型转换问题:map.get("stars")返回Option[Set[HeavenlyBody]],调用toSeq后得到Seq[Set[HeavenlyBody]],但Stars构造器需要的是Seq[CreateStar],类型不兼容;同时存储的HeavenlyBody需要转型为具体子类。
  2. 不可变Map更新错误:原代码中map("stars") += star试图直接修改不可变Map,这在Scala中不允许,必须生成新的Map实例。

修复后的代码

修改StarRegistry.scala中的核心逻辑,解决类型转换和Map更新问题:

sealed trait HeavenlyBody

final case class CreateStar(id: String, name: String, location: String, size: Option[Size]) extends HeavenlyBody
final case class CreatePlanet(id: String, name: String, location: String, size: Option[Size]) extends HeavenlyBody
final case class CreateMoon(id: String, name: String, location: String, size: Option[Size]) extends HeavenlyBody

final case class Stars(stars: immutable.Seq[CreateStar])
final case class Planets(planets: immutable.Seq[CreatePlanet]) 
final case class Moons(moons: immutable.Seq[CreateMoon]) 

final case class Size(radius: Long)

object StarRegistry {

  // actor protocol
  sealed trait Command
  final case class GetStars(replyTo: ActorRef[Stars]) extends Command
  final case class NewStar(star: CreateStar, replyTo: ActorRef[ActionPerformed]) extends Command

  final case class GetPlanets(replyTo: ActorRef[Planets]) extends Command
  final case class NewPlanet(planet: CreatePlanet, replyTo: ActorRef[ActionPerformed]) extends Command

  final case class GetMoons(replyTo: ActorRef[Moons]) extends Command
  final case class NewMoon(moon: CreateMoon, replyTo: ActorRef[ActionPerformed]) extends Command

  final case class ActionPerformed(description: String)

  // 初始化时明确每个Set的类型
  def apply(): Behavior[Command] = registry(
    Map(
      "stars" -> Set.empty[CreateStar].asInstanceOf[Set[HeavenlyBody]],
      "planets" -> Set.empty[CreatePlanet].asInstanceOf[Set[HeavenlyBody]],
      "moons" -> Set.empty[CreateMoon].asInstanceOf[Set[HeavenlyBody]]
    )
  )

  private def registry(map: Map[String, Set[HeavenlyBody]]): Behavior[Command] =
    Behaviors.receiveMessage {

      case GetStars(replyTo) =>
        // 取出Set并安全转型为CreateStar,再转为Seq
        val stars = map.getOrElse("stars", Set.empty).collect { case s: CreateStar => s }.toSeq
        replyTo ! Stars(stars)
        Behaviors.same
      case NewStar(star, replyTo) =>
        replyTo ! ActionPerformed(s"Star '${star.name}' created!")
        // 更新不可变Map,生成新实例
        val updatedStars = map("stars") + star
        registry(map.updated("stars", updatedStars))

      case GetPlanets(replyTo) =>
        val planets = map.getOrElse("planets", Set.empty).collect { case p: CreatePlanet => p }.toSeq
        replyTo ! Planets(planets)
        Behaviors.same
      case NewPlanet(planet, replyTo) =>
        replyTo ! ActionPerformed(s"Planet '${planet.name}' created!")
        val updatedPlanets = map("planets") + planet
        registry(map.updated("planets", updatedPlanets))

      case GetMoons(replyTo) =>
        val moons = map.getOrElse("moons", Set.empty).collect { case m: CreateMoon => m }.toSeq
        replyTo ! Moons(moons)
        Behaviors.same
      case NewMoon(moon, replyTo) =>
        replyTo ! ActionPerformed(s"Moon '${moon.name}' created!")
        val updatedMoons = map("moons") + moon
        registry(map.updated("moons", updatedMoons))

    }
}

关键修改点

  1. 初始化Map:明确每个初始Set的类型,通过asInstanceOf转为Set[HeavenlyBody],确保类型兼容。
  2. 查询时类型转换:使用collect安全地将HeavenlyBody转型为具体子类,避免强制转换的风险,再转为Seq。
  3. 更新不可变Map:使用map.updated生成新的Map实例,替换原有的键值对,符合Scala不可变集合的使用规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:59:54