没有同伴的顶级 class 只能扩展为同名 class 或由同名同伴组成的块
top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
我正在尝试按如下方式使用 https://github.com/estatico/scala-newtype:
import io.estatico.newtype.macros.newtype
import cats._
import io.databaker.env._
@newtype case class DbUrl(v: String)
@newtype case class DbUser(v: String)
@newtype case class DbPw(v: String)
final case class DbParams(url: DbUrl, user: DbUser, pw: DbPw)
trait DbConnector[F[_]] {
def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams]
}
object DbConnector {
def impl[F[_] : MonadError[*[_], Throwable]](env: Environment[F])
: DbConnector[F] =
new LiveDbConnector[F](env)
}
编译器抱怨:
[error] ../db/DbConnector.scala:7:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class DbUrl(v: String)
[error] ^
[error] ../db/DbConnector.scala:9:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class DbUser(v: String)
[error] ^
[error] ../db/DbConnector.scala:11:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class DbPw(v: String)
[error] ^
[error] ../env/Environment.scala:8:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class EnvValue(v: String)
[error] ^
[error] ../env/Environment.scala:6:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class EnvVariable(v: String)
build.sbt
内容:
lazy val root = (project in file("."))
.enablePlugins(JettyPlugin)
.settings(
organization := "io.example",
name := "user-svc",
version := "0.0.1-SNAPSHOT",
scalaVersion := "2.13.2",
mainClass := Some("io.example.Main"),
containerPort := 9090,
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-servlet" % Http4sVersion,
"org.http4s" %% "http4s-circe" % Http4sVersion,
"org.http4s" %% "http4s-dsl" % Http4sVersion,
"io.circe" %% "circe-generic" % CirceVersion,
"org.scalameta" %% "munit" % MunitVersion % "test",
"ch.qos.logback" % "logback-classic" % LogbackVersion,
"io.estatico" %% "newtype" % NewTypeVersion,
"javax.servlet" % "javax.servlet-api" % ServletVersion % "provided"
),
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full),
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1"),
)
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
"-language:higherKinds",
"-language:postfixOps",
"-feature",
"-Xfatal-warnings",
"-Ymacro-annotations"
)
我做错了什么?
更新
我已将 newtype 宏移动到包对象中,如下所示:
package object db {
@newtype case class DbUrl(v: String)
@newtype case class DbUser(v: String)
@newtype case class DbPw(v: String)
}
但编译器仍然报错:
implicit conversion method opsThis should be enabled
[error] by making the implicit value scala.language.implicitConversions visible.
[error] @newtype case class DbUser(v: String)
scala-newtype 的 README.md 说:
This expands into a type and companion object definition, so newtypes must be defined in an object or package object.
宏可以扩展 classes 到其他具有相同名称和伴随对象的 classes,但据我所知,newtype
注释将你的 case class
到一个同名的对象中(连同类型别名,如 type DbUrl = DbUrl.Type
)。这种行为(将顶级注释者变成某种其他类型的树)是不允许的。如果注解生成了一个 class DbUrl
,也许还有一个同名的对象,那么它就没问题了,但几乎所有其他东西都不起作用。
要解决您的问题,您需要做的就是将其移动到一个包对象中(或其他范围,只要它不是顶级的)。
编辑:正如 Dmytro Mitin 指出的那样,创建的类型不是 DbUrl
的类型,而是类似 type DbUrl = DbUrl.Type
的大写“T”,其中 [=17= 的定义] 看起来像这样(我只是从自述文件中复制它):
type Base = Any { type DbUrl$newtype }
trait Tag extends Any
type Type <: Base with Tag
我正在尝试按如下方式使用 https://github.com/estatico/scala-newtype:
import io.estatico.newtype.macros.newtype
import cats._
import io.databaker.env._
@newtype case class DbUrl(v: String)
@newtype case class DbUser(v: String)
@newtype case class DbPw(v: String)
final case class DbParams(url: DbUrl, user: DbUser, pw: DbPw)
trait DbConnector[F[_]] {
def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams]
}
object DbConnector {
def impl[F[_] : MonadError[*[_], Throwable]](env: Environment[F])
: DbConnector[F] =
new LiveDbConnector[F](env)
}
编译器抱怨:
[error] ../db/DbConnector.scala:7:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class DbUrl(v: String)
[error] ^
[error] ../db/DbConnector.scala:9:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class DbUser(v: String)
[error] ^
[error] ../db/DbConnector.scala:11:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class DbPw(v: String)
[error] ^
[error] ../env/Environment.scala:8:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class EnvValue(v: String)
[error] ^
[error] ../env/Environment.scala:6:2: top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions
[error] @newtype case class EnvVariable(v: String)
build.sbt
内容:
lazy val root = (project in file("."))
.enablePlugins(JettyPlugin)
.settings(
organization := "io.example",
name := "user-svc",
version := "0.0.1-SNAPSHOT",
scalaVersion := "2.13.2",
mainClass := Some("io.example.Main"),
containerPort := 9090,
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-servlet" % Http4sVersion,
"org.http4s" %% "http4s-circe" % Http4sVersion,
"org.http4s" %% "http4s-dsl" % Http4sVersion,
"io.circe" %% "circe-generic" % CirceVersion,
"org.scalameta" %% "munit" % MunitVersion % "test",
"ch.qos.logback" % "logback-classic" % LogbackVersion,
"io.estatico" %% "newtype" % NewTypeVersion,
"javax.servlet" % "javax.servlet-api" % ServletVersion % "provided"
),
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full),
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1"),
)
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
"-language:higherKinds",
"-language:postfixOps",
"-feature",
"-Xfatal-warnings",
"-Ymacro-annotations"
)
我做错了什么?
更新
我已将 newtype 宏移动到包对象中,如下所示:
package object db {
@newtype case class DbUrl(v: String)
@newtype case class DbUser(v: String)
@newtype case class DbPw(v: String)
}
但编译器仍然报错:
implicit conversion method opsThis should be enabled
[error] by making the implicit value scala.language.implicitConversions visible.
[error] @newtype case class DbUser(v: String)
scala-newtype 的 README.md 说:
This expands into a type and companion object definition, so newtypes must be defined in an object or package object.
宏可以扩展 classes 到其他具有相同名称和伴随对象的 classes,但据我所知,newtype
注释将你的 case class
到一个同名的对象中(连同类型别名,如 type DbUrl = DbUrl.Type
)。这种行为(将顶级注释者变成某种其他类型的树)是不允许的。如果注解生成了一个 class DbUrl
,也许还有一个同名的对象,那么它就没问题了,但几乎所有其他东西都不起作用。
要解决您的问题,您需要做的就是将其移动到一个包对象中(或其他范围,只要它不是顶级的)。
编辑:正如 Dmytro Mitin 指出的那样,创建的类型不是 DbUrl
的类型,而是类似 type DbUrl = DbUrl.Type
的大写“T”,其中 [=17= 的定义] 看起来像这样(我只是从自述文件中复制它):
type Base = Any { type DbUrl$newtype }
trait Tag extends Any
type Type <: Base with Tag