Aşağıdaki makro, ShapelessillTyped
'un bir dize olarak sağladığınız bazı kodları tekrar yazmayı deneyen basitleştirilmiş bir sürümüdür. Başarısız olursa None
döndürür ve başarısız olursaistisnası.Bu kod neden Scala 2.11'de yazıyor ve bu konuda ne yapabilirim?
import scala.language.experimental.macros
import scala.reflect.macros.TypecheckException
import scala.reflect.macros.whitebox.Context
def typecheck_impl(c: Context)(code: c.Expr[String]): c.Expr[Option[String]] = {
import c.universe._
val Expr(Literal(Constant(codeStr: String))) = code
try {
c.typecheck(c.parse(codeStr))
c.Expr(q"None: Option[String]")
} catch {
case e: TypecheckException =>
c.Expr(q"Some(${ e.toString }): Option[String]")
}
}
def typecheck(code: String): Option[String] = macro typecheck_impl
Şimdi varsayalım Foo
vaka sınıfına sahibim. Bir vaka sınıfı olduğundan, Foo
bunun için otomatik olarak oluşturulan bir aspiratör var ama en de aynı şeyi yapar kendi çıkarıcı Bar
tanımlayalım olacaktır:
scala> import Test._
import Test._
scala> val Foo(x, y) = Foo(1, 'a')
x: Int = 1
y: Char = a
scala> val Bar(x, y) = Foo(1, 'a')
x: Int = 1
y: Char = a
scala> val Foo(x, y, z) = Foo(1, 'a')
<console>:15: error: wrong number of arguments for pattern Test.Foo(i: Int,c: Char)
val Foo(x, y, z) = Foo(1, 'a')
^
scala> val Bar(x, y, z) = Foo(1, 'a')
<console>:15: error: too many patterns for object Bar offering (Int, Char): expected 2, found 3
val Bar(x, y, z) = Foo(1, 'a')
^
scala> typecheck("val Foo(x, y) = Foo(1, 'a')")
res0: Option[String] = None
scala> typecheck("val Bar(x, y) = Foo(1, 'a')")
res1: Option[String] = None
scala> typecheck("val Foo(x, y, z) = Foo(1, 'a')")
res2: Option[String] = Some(scala.reflect.macros.TypecheckException: wrong number of arguments for pattern Test.Foo(i: Int,c: Char))
:
object Test {
case class Foo(i: Int, c: Char)
object Bar {
def unapply(foo: Foo): Option[(Int, Char)] = Some((foo.i, foo.c))
}
}
Şimdi aşağıdaki yazabilirsiniz
Bunların hiçbiri şaşırtıcı değil - derlemeleri derleyeceğiniz şeyler, yapamayacağınız şeyler ve makromuz kabul eder. Ancak, bunu deneyin:
Ve makro sadece boğuluyor. Herhangi bir eski atılabilirliği işlemek için catch
bloğunu değiştirmek aynı sonucu verir. Eşdeğer kod 2.10'da beklendiği gibi çalıştı.
Makromumun 2.11'de beklendiği gibi çalışabilmesi için bu hatayı nasıl alabilirim?
İyi soru. ScalaDays'tan sonra düşünmem gerek. Bu senin işine yarar mıydı? –
Elbette, Eugene - acele etmeyin, teşekkürler! Buna bir dalda Shapeless'ın “Sized” çıkarıcısı için bazı değişiklikler yaptım, ama bu hiç de acil değil (şube zaten aylık). –
https://issues.scala-lang.org/browse/SI-8719 –