Makro implisit. Nilai implisit default. Bagaimana?

Sep 29 2020

Saya bahkan tidak tahu bagaimana mengajukan pertanyaan itu.

Saya memiliki makro yang membuat instance IsEnum[T]untuk suatu tipe T.

Saya melakukan pengujian untuk itu, dan ingin memastikan bahwa implisit tidak ditemukan untuk tipe yang tidak disegel, atau yang, secara umum, tidak memenuhi persyaratan enum.

Jadi saya membuat metode ini untuk pengujian

    def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum

Dan kemudian saya memastikan itu enumOf[NotAnEnum] == null

Namun sebaliknya, gagal pada waktu kompilasi.

Satu hal adalah kesalahan makro. Hal lain adalah makro tidak berlaku untuk kasus tertentu. Bagaimana cara membuat perbedaan itu saat membuat makro?

Sunting: Saya telah menggunakan c.abortdan c.error, keduanya memberi saya hasil yang sama.

Jawaban

2 DmytroMitin Sep 29 2020 at 23:43

Kedengarannya seperti Anda tidak membuat kotak IsEnumputih kelas jenis terwujud makro Anda . Biasanya makro implisit harus kotak putih.

import scala.language.experimental.macros
import scala.reflect.macros.whitebox

trait IsEnum[T]
object IsEnum {
  implicit def mkIsEnum[T]: IsEnum[T] = macro mkIsEnumImpl[T]
  def mkIsEnumImpl[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._
    val typ = weakTypeOf[T]
    val classSymbol = typ.typeSymbol.asClass
    if (!classSymbol.isTrait || !classSymbol.isSealed) c.abort(c.enclosingPosition, s"$typ must be sealed trait") val symbols = classSymbol.knownDirectSubclasses symbols.collectFirst { case symbol if !symbol.isModuleClass || !symbol.asClass.isCaseClass => c.abort(c.enclosingPosition, s"${symbol.asClass.toType} must be case object")
    }
    q"new IsEnum[$typ] {}"
  }
}

def enumOf[T](implicit isEnum: IsEnum[T] = null) = isEnum

Pemakaian:

sealed trait A
object A {
  case object B extends A
  case object C extends A
  case class D() extends A
}
enumOf[A] //null

sealed trait A
object A {
  case object B extends A
  case object C extends A
  class D extends A
}
enumOf[A] //null

sealed trait A
object A {
  case object B extends A
  object C extends A
}
enumOf[A] //null

trait A
object A {
  case object B extends A
  case object C extends A
}
enumOf[A] //null

sealed trait A
object A {
  case object B extends A
  case object C extends A
}
enumOf[A] //App$$anon$1@47f37ef1

Waktu kerja makro adalah waktu kompilasi kode utama. Jika makro kotak hitam (bahkan makro kotak hitam implisit) melontarkan pengecualian, maka itu akan menjadi kesalahan kompilasi selama kompilasi kode utama. Jika makro implisit kotak putih melontarkan pengecualian maka selama kompilasi kode utama, implisit akan dihapus secara diam-diam dari kandidat.

https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html