Julia体验 语言特性 元编程,宏
上接语言基础,个人感觉这门语言和自己心中的理想国相距较远,乘着热情还在,我挑一些有趣的东西再写写。
元编程
元编程即对代码进行处理的代码,可以使用Meta.parse()
解析出参数代码的类AST表示,也可以使用quote ... end
简化:
julia> multiStmt = Meta.parse(raw"a=1;b=2;t=a;a=b;b=t;println(a,b)")
:($(Expr(:toplevel, :(a = 1), :(b = 2), :(t = a), :(a = b), :(b = t), :(println(a, b)))))
julia> typeof(multiStmt)
Expr
julia> ast = quote
x=1
y=2
res=x+y
end
quote
#= REPL[21]:2 =#
x = 1
#= REPL[21]:3 =#
y = 2
#= REPL[21]:4 =#
res = x + y
end
julia> typeof(ast)
Expr
使用dump()
获得更可读的表示:
julia> dump(multiStmt)
Expr
head: Symbol toplevel
args: Array{Any}((6,))
1: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol a
2: Int64 1
2: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol b
2: Int64 2
3: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol t
2: Symbol a
4: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol a
2: Symbol b
5: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol b
2: Symbol t
6: Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol println
2: Symbol a
3: Symbol b
expr有两部分,expr.head
表示出这个表达式的类型,expr.args
表示出剩余的参数:
julia> multiStmt.head
:toplevel
julia> multiStmt.args
6-element Array{Any,1}:
:(a = 1)
:(b = 2)
:(t = a)
:(a = b)
:(b = t)
:(println(a, b))
如果我们typeof head会发现,它是一种名为Symbol
的类型:
julia> typeof(multiStmt.head)
Symbol
Symbol类型可以使用:name
进行定义,也可以使用Symbol类型的构造创建:
julia> :str
:str
julia> typeof(:str)
Symbol
julia> Symbol("str2")
:str2
julia> typeof(Symbol("str2"))==typeof(:str)
true
最后我们使用eval()
h函数传入Expr类型参数求值:
julia> eval(ast)
3
julia> eval(multiStmt)
21
这就给了我们一种使用代码操纵代码的方式:
julia> add = Expr(:call,:-,:a,:b)
:(a - b)
julia> a = 1
1
julia> b= 2
2
julia> eval(add)
-1
宏
Julia的宏由macro ... end
定义
julia> macro hello(name)
return "hello,my name is "*name
end
@hello (macro with 1 method)
julia> println(@hello("Andrew"))
hello,my name is Andrew
julia> println(@hello "Andrew")
hello,my name is Andrew
使用宏可以像函数一样加括号也可以宏名 参数1 参数2 ...
类似C/C++的宏的概念,Julia的宏也是实施的替换操作
所以上述println(@hello "Andrew")
会被替换为println("hello, my name is Andrew")
,可以使用@macroexpand
获得展开后的结果
julia> @macroexpand println(@hello "Andrew")
:(println("hello,my name is Andrew"))