Scala 强制执行案例对象的名称
鉴于此代码:Scala 强制执行案例对象的名称,scala,functional-programming,Scala,Functional Programming,鉴于此代码: sealed trait Parent case object GetOne extends Parent case object GetTwo extends Parent 在Scala中是否可以强制执行这些约束: 父对象只能按大小写对象扩展 父对象的子事例对象的名称必须以Get开头。 可能吗 父对象只能按大小写对象扩展 你可能会接近使用。 如@MateuszKubuszok所述 以下是一个例子: sealed trait Foo extends Product with S
sealed trait Parent
case object GetOne extends Parent
case object GetTwo extends Parent
在Scala中是否可以强制执行这些约束:
父对象只能按大小写对象扩展
父对象的子事例对象的名称必须以Get开头。
可能吗
父对象只能按大小写对象扩展
你可能会接近使用。
如@MateuszKubuszok所述
以下是一个例子:
sealed trait Foo extends Product with Serializable { self: Singleton => }
那么这就行了:
final case object A extends Foo
final case object B extends Foo
但这并不是:
final case object A extends Foo
final case class B(blah: String) extends Foo
父对象的子事例对象的名称必须以Get开头
不使用标准Scala。
也许是宏或类似的东西,但真的感觉像是一个奇怪的必要条件;您是否计划通过反射获得这些实例?或者是什么原因想要这样
在任何情况下,代码审查和scalafix规则似乎可以更好地处理这一问题
父对象只能按大小写对象扩展
在Scala 3中,您可以定义
强制成员成为有效的大小写对象。尝试使用无形状宏
import shapeless.ops.{coproduct, hlist}
import shapeless.{Coproduct, HList, LabelledGeneric}
import shapeless.ops.union.{Keys, Values}
def check[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[C <: Coproduct, K <: HList, V <: Coproduct]()(implicit
labelledGeneric: LabelledGeneric.Aux[A, C],
keys: Keys.Aux[C, K],
values: Values.Aux[C, V],
allKeysStartWithGet: hlist.LiftAll[StartsWithGet, K],
allValuesAreObjects: coproduct.LiftAll[IsObject, V]
) = null
}
import shapeless.Witness
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait StartsWithGet[S]
object StartsWithGet {
implicit def mkStartsWithGet[S <: Symbol]: StartsWithGet[S] = macro impl[S]
def impl[S <: Symbol : c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[S]
val witness = c.inferImplicitValue(
c.typecheck(tq"_root_.shapeless.Witness.Aux[$typ]", mode = c.TYPEmode).tpe,
silent = false
)
val str = c.eval(c.Expr[Witness.Lt[scala.Symbol]](
c.untypecheck(witness.duplicate)
)).value.name
if (str.startsWith("Get"))
q"new StartsWithGet[$typ] {}"
else c.abort(c.enclosingPosition, s"$str doesn't start with Get")
}
}
trait IsObject[A]
object IsObject {
implicit def mkIsObject[A]: IsObject[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[A]
if (typ.typeSymbol.isModuleClass)
q"new IsObject[$typ] {}"
else c.abort(c.enclosingPosition, s"$typ is not object")
}
}
sealed trait Parent
case object GetOne extends Parent
case object GetTwo extends Parent
check[Parent]() // compiles
sealed trait Parent
case object GetOne extends Parent
case object Two extends Parent
check[Parent]() // doesn't compile
sealed trait Parent
case object GetOne extends Parent
case class GetTwo() extends Parent
check[Parent]() // doesn't compile
1.好吧,您最多可以要求父级按产品进行扩展,并使用Singleton进行序列化。2.我想,您可以让parent接受一些隐式参数,这些参数将根据子对象的名称进行解析,并使此隐式参数仅适用于以get开头的名称,使用一些宏。。。基本上类似于密封的抽象类父类[T:StartWithGet]{this:T with Product with Serializable with Singleton},其中StartWithGet[T]仅由宏为名称以get开头的类提供。但这太糟糕了。或者,我的答案中的StartsWithGet可以通过导入shapeless.tag来定义。@@import singleton.ops.{Require,StartsWithGet}trait StartsWithGet[S]对象StartsWithGet{implicit def mkStartsWithGet[S我在Scala 2.11,2.12中,谢谢!这很有帮助
import shapeless.ops.{coproduct, hlist}
import shapeless.{Coproduct, HList, LabelledGeneric}
import shapeless.ops.union.{Keys, Values}
def check[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[C <: Coproduct, K <: HList, V <: Coproduct]()(implicit
labelledGeneric: LabelledGeneric.Aux[A, C],
keys: Keys.Aux[C, K],
values: Values.Aux[C, V],
allKeysStartWithGet: hlist.LiftAll[StartsWithGet, K],
allValuesAreObjects: coproduct.LiftAll[IsObject, V]
) = null
}
import shapeless.Witness
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait StartsWithGet[S]
object StartsWithGet {
implicit def mkStartsWithGet[S <: Symbol]: StartsWithGet[S] = macro impl[S]
def impl[S <: Symbol : c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[S]
val witness = c.inferImplicitValue(
c.typecheck(tq"_root_.shapeless.Witness.Aux[$typ]", mode = c.TYPEmode).tpe,
silent = false
)
val str = c.eval(c.Expr[Witness.Lt[scala.Symbol]](
c.untypecheck(witness.duplicate)
)).value.name
if (str.startsWith("Get"))
q"new StartsWithGet[$typ] {}"
else c.abort(c.enclosingPosition, s"$str doesn't start with Get")
}
}
trait IsObject[A]
object IsObject {
implicit def mkIsObject[A]: IsObject[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[A]
if (typ.typeSymbol.isModuleClass)
q"new IsObject[$typ] {}"
else c.abort(c.enclosingPosition, s"$typ is not object")
}
}
sealed trait Parent
case object GetOne extends Parent
case object GetTwo extends Parent
check[Parent]() // compiles
sealed trait Parent
case object GetOne extends Parent
case object Two extends Parent
check[Parent]() // doesn't compile
sealed trait Parent
case object GetOne extends Parent
case class GetTwo() extends Parent
check[Parent]() // doesn't compile
import shapeless.tag.@@
import singleton.ops.{Require, StartsWith}
trait StartsWithGet[S]
object StartsWithGet {
implicit def mkStartsWithGet[S <: String](implicit
startsWith: Require[S StartsWith "Get"]
): StartsWithGet[Symbol @@ S] = null
}