假设我有一个函数/方法:
class A {
def function() = {
subroutine("A")
...
subroutine("B")
...
subroutine("C")
}
def subroutine(a: String) = { ... }
}
是否可以使用Scala反射编程在函数()中查找子程序(a:String)的所有3个调用,而不调用function()本身? (这可能需要很长的时间)
答案 0 :(得分:1)
您可以尝试通过一些很酷的功能工具来解决这个问题,而不需要内省。
让我们使用scalaz library它有特殊的类型Arrow
,它是import scalaz._
import scalaz.syntax.tree._
import scalaz.std.function._
import scalaz.syntax.arrow._
import scalaz.std.string._
case class Subroutine[-A, +B](hier: Seq[Tree[String]], run: A => B) {
def named(name: String) = Subroutine(Seq(name.node(hier: _*)), run)
def printHier = hier.map(_.drawTree).mkString("\n" + "V" * 15 + "\n")
}
object Subroutine {
def named[A, B](tag: String)(run: A => B) = Subroutine(Seq(tag.leaf), run)
implicit def anon[A, B](run: A => B) = Subroutine(Seq.empty, run)
implicit object subroutineArrow extends Arrow[Subroutine] {
def arr[A, B](f: (A) => B): Subroutine[A, B] = anon(f)
def first[A, B, C](f: Subroutine[A, B]): Subroutine[(A, C), (B, C)] =
Subroutine(f.hier, f.run.first[C]).named("$1->")
override def second[A, B, C](f: Subroutine[A, B]): Subroutine[(C, A), (C, B)] =
Subroutine(f.hier, f.run.second[C]).named("$2->")
def id[A]: Subroutine[A, A] = anon(identity)
def compose[A, B, C](f: Subroutine[B, C], g: Subroutine[A, B]): Subroutine[A, C] =
Subroutine(g.hier ++ f.hier, f.run compose g.run)
}
}
的抽象。
它允许你做任何你通常用函数做的事情
因此,让我们定义一个特殊的类型,它不仅包含函数,而且以一种可读的方式调用层次结构。
import Subroutine._
val square = { (x: Double) => x * x } named "square"
val sqrt = math.sqrt _ named "sqrt"
val sum = Subroutine.named[(Double, Double), Double]("sum"){ case (x, y) => x + y}
val abs = ((square *** square) >>> sum >>> sqrt) named "abs"
现在让我们定义一些子程序
abs.run(3,4)
从这里你可以验证
5.0
给出结果abs.printHier
而
"abs"
|
+- "$1->"
| |
| `- "square"
|
+- "$2->"
| |
| `- "square"
|
+- "sum"
|
`- "sqrt"
给出有趣的通话顺序,如
def pack22[X] = Subroutine.anon[(X, X, X, X), ((X, X), (X, X))] { case (a, b, c, d) => ((a, b), (c, d)) }
val abs4 = ((abs *** abs) >>> abs <<< pack22[Double]) named "abs4"
甚至定义
abs4.run(15, 20, 36, 48)
并评估
abs4.printHier
和
<!DOCTYPE html>
<html>
<head>
<title>Slideout menu</title>
<style>
.menu{
overflow-x: hidden;
position: relative;
left: 0;
}
.menu-open{
left: 231px;
}
.menu-open .menu-side{
left: 0;
}
.menu-side,.menu{
-webkit-transition: left 0.2s ease;
-moz-transition: left 0.2s ease;
transition: left 0.2s ease;
}
.menu-side{
background-color: #333;
border-right: 1px solid #000;
color:#fff;
position: fixed;
top: 0;
left: -231px;
width: 210px;
height: 100%;
padding: 10px;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body class="menu">
<header>
<a href="#" class="menu-toggel">toggel button</a>
<nav class="menu-side">
this is a site menu
<form action="" method="post">
<input type="text" name="titel" value="data to send when submit" id="name">
<input type="submit" value="register">
</form>
</nav>
</header>
<form action="" method="post">
<label for="titel">Titel</label>
<input type="text" name="titel" value="data to send when submit" id="name">
<label for="omschrijving">omschrijving</label>
<input type="text" name="omschrijving" id="omschrijving" value="data to send when submit" autocomplete="off">
<label for="email">Uw emailadres</label>
<input type="text" name="email" id="email" value="data to send when submit">
<label for="naam">Uw naam</label>
<input type="text" name="naam" id="naam" value="data to send when submit">
</form>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
(function() {
var body = $('body');
$('.menu-toggel').bind('click', function(){
body.toggleClass('menu-open');
return false;
});
})();
</script>