如何使用shapeless检测字段类型注释 [英] how to use shapeless to detect field type annotation

查看:35
本文介绍了如何使用shapeless检测字段类型注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 shapeless 收集在编译时具有特定注释的案例类的字段.我尝试使用以下代码段,但它没有按预期工作(不输出任何内容而不是打印i").我怎样才能让它工作?

I am trying to gather the fields of a case class that have a particular annotations at compile time using shapeless. I tried to play around the following snippet, but it did not work as expected (output nothing instead of printing "i"). How can I make it work ?

import shapeless._
import shapeless.labelled._

final class searchable() extends scala.annotation.StaticAnnotation
final case class Foo(@searchable i: Int, s: String)

trait Boo[A] {
  def print(a: A): Unit
}
sealed trait Boo0 {
  implicit def hnil = new Boo[HNil] { def print(hnil: HNil): Unit = () }
  implicit def hlist[K <: Symbol, V, RL <: HList](implicit b: Boo[RL]): Boo[FieldType[K, V] :: RL] =
    new Boo[FieldType[K, V] :: RL] {
      def print(a: FieldType[K, V] :: RL): Unit = {
        b.print(a.tail)
      }
    }
}
sealed trait Boo1 extends Boo0 {
  implicit def hlist1[K <: Symbol, V, RL <: HList](implicit annot: Annotation[searchable, K], witness: Witness.Aux[K], b: Boo[RL]): Boo[FieldType[K, V] :: RL] =
    new Boo[FieldType[K, V] :: RL] {
      def print(a: FieldType[K, V] :: RL): Unit = {
        Console.println(witness.value.name)
        b.print(a.tail)
      }
    }
}
object Boo extends Boo1 {
  implicit def generics[A, HL <: HList](implicit iso: LabelledGeneric.Aux[A, HL], boo: Boo[HL]): Boo[A] =
    new Boo[A] {
      def print(a: A): Unit = {
        boo.print(iso.to(a))
      }
    }
}

implicitly[Boo[Foo]].print(Foo(1, "2"))

推荐答案

Annotation的宏,直接拒绝不是产品或副产品的类型

Looking at the macro of Annotation, it rejects type that is not a product or coproduct straight up

val annTreeOpts =
  if (isProduct(tpe)) { ... }
  else if (isCoproduct(tpe)) { ... }
  else abort(s"$tpe is not case class like or the root of a sealed family of types")

这很不幸,因为在每个字段符号级别收集类型注释有时可能非常有用.

this is quite unfortunate, as collecting type annotations at per field symbol level could be quite useful sometimes.

在同一个文件中定义了另一个类型类Annotations,它实际上可以将字段上的特定注释收集到一个HList中.然而问题是字段信息完全丢失.有一种笨拙的方法可以将事物组合在一起以服务于我的用例......

There is another type class Annotations defined in the same file that can actually collect particular annotations on field into an HList. However problem is the field information is totally lost. There is a clumsy way to hack things together to serve my use case...

// A is our annotation
// B is our result type    
// C is our case class with some fields annotated with A

def empty: B = ???
def concat(b1: B, b2: B): B = ???
def func(a: A, nm: String): B = ???

object Collector extends Poly2 {
   implicit def some[K <: Symbol](implicit witness: Witness.Aux[K]) = 
     at[B, (K, Some[A])] { case (b, (_, a)) => concat(b, func(a.get, witness.value.name)) }
   implicit def none[K <: Symbol] = at[B, (K, None.type)] { case (b, _) => b }
}

def collect[HL <: HList, RL <: HList, KL <: HList, ZL <: HList](implicit 
    iso: LabelledGeneric.Aux[C, HL]
  , annot: Annotations.Aux[A, C, RL]
  , keys: Keys.Aux[HL, KL]
  , zip: Zip.Aux[KL :: RL :: HNil, ZL]
  , leftFolder: LeftFolder.Aux[ZL, B, Collector.type, B]): B = {
  zip(keys() :: annot() :: HNil).foldLeft(empty)(Collector)
}

这篇关于如何使用shapeless检测字段类型注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆