Trước hết, trường hợp 1 + "foo"
sẽ là khó khăn vì không có thực sự bất kỳ chuyển đổi ngầm xảy ra ở đó: Int
tự really, truly does have this +
method (unfortunately).
Vì vậy, bạn không may mắn nếu đó là trường hợp sử dụng của bạn, nhưng bạn có thể làm những gì bạn mô tả thường xuyên hơn. Tôi sẽ giả thiết lập sau trong ví dụ của tôi dưới đây:
case class Foo(i: Int)
case class Bar(s: String)
implicit def foo2bar(foo: Foo) = Bar(foo.i.toString)
đầu tiên cho phương pháp tiếp cận thanh lịch:
object ConversionDetector {
import scala.language.experimental.macros
import scala.reflect.macros.Context
def sniff[A](tree: _): Boolean = macro sniff_impl[A]
def sniff_impl[A: c.WeakTypeTag](c: Context)(tree: c.Tree) = {
// First we confirm that the code typechecks at all:
c.typeCheck(tree, c.universe.weakTypeOf[A])
// Now we try it without views:
c.literal(
c.typeCheck(tree, c.universe.weakTypeOf[A], true, true, false).isEmpty
)
}
}
Những công trình như mong muốn:
scala> ConversionDetector.sniff[Bar](Foo(42))
res1: Boolean = true
scala> ConversionDetector.sniff[Bar](foo2bar(Foo(42)))
res2: Boolean = false
Đáng tiếc là điều này đòi hỏi các macro untyped, hiện chỉ có sẵn trong Macro Paradise.
Bạn có thể có được những gì bạn muốn với đồng bằng cũ def
macro trong 2.10, nhưng đó là một chút của một hack:
object ConversionDetector {
import scala.language.experimental.macros
import scala.reflect.macros.Context
def sniff[A](a: A) = macro sniff_impl[A]
def sniff_impl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = {
import c.universe._
c.literal(
a.tree.exists {
case app @ Apply(fun, _) => app.pos.column == fun.pos.column
case _ => false
}
)
}
}
Và một lần nữa:
scala> ConversionDetector.sniff[Bar](Foo(42))
res1: Boolean = true
scala> ConversionDetector.sniff[Bar](foo2bar(Foo(42)))
res2: Boolean = false
Bí quyết là để tìm kiếm nơi nơi chúng ta thấy ứng dụng chức năng trong cây cú pháp trừu tượng của chúng ta, và sau đó kiểm tra xem các vị trí của nút Apply
và con của nó có cùng một cột hay không, cho biết rằng lời gọi phương thức không hiển thị rõ ràng trong nguồn.
Cảm ơn đã trả lời. Tôi không biết rằng 'Int' có một phương thức' + 'chấp nhận' String' nhưng tôi có nghĩa là trường hợp chung. Tôi đã suy nghĩ về việc sử dụng 'Vị trí quá, nhưng điều này thực sự có mùi một chút 'hacky'. Tôi nghĩ sẽ rất tuyệt nếu 'Tree's có một số lá cờ có thể nói" cây này được trình biên dịch tự động suy ra ". – ghik
Tôi vừa tìm thấy một [bình luận] (https://github.com/scala/scala/blob/master/src/reflect/scala/reflect/internal/Trees.scala#L431) trong các nguồn 'scala-reflect' mà nói về một số cờ tiềm năng trên AST 'Áp dụng' sẽ chỉ ra chuyển đổi ngầm định. Và có vẻ như bây giờ có một lớp riêng biệt để chỉ ra điều này (nó là nội bộ, thật không may). – ghik
Thật không may bằng cách sử dụng thủ thuật 'Position' sẽ có nghĩa là mã của bạn sẽ bị thổi khi được sử dụng trong REPL. @ghik, tôi nghĩ rằng bạn đang đi đúng hướng với bình luận cuối cùng của mình, câu trả lời của EugeneBurmako là gì. –