julia学习笔记(六):模块、宏和元编程

模块

模块(module)是一些互相隔离的可变工作空间,也就是说它们会引入新的全局作用域。它们在语法上以 module Name … end 界定。模块允许你创建顶层定义(也称为全局变量),而无需担心命名冲突。在模块中,利用导入(importing)可以控制其它模块中的哪些名称是可见的;利用导出(exporting)可以控制你自己的模块中的哪些名称是公开的。

julia> module MyModule
       export my_add, my_multiply

       my_add(x, y) = x + y
       my_multiply(x, y) = x * y
       my_minus(x, y) = x - y
       my_pow(x, y) = x ^ y
       my_abs(x) = x >= 0 ? x : -x
       end
Main.MyModule

# using后,export的方法可以直接使用
julia> my_add(1, 2)
3

julia> my_multiply(3, 4)
12

# 没有export的方法需要import
julia> my_minus(4, 3)
ERROR: UndefVarError: my_minus not defined
Stacktrace:
	...

julia> import Main.MyModule.my_minus

julia> my_minus(4, 3)
1

# 也可以用全名访问模块内方法
julia> Main.MyModule.my_abs(-5)
5

模块和文件

模块与文件和文件名无关;模块只与模块表达式有关。一个模块可以有多个文件,一个文件也可以有多个模块。

标准模块

有三个重要的标准模块:

  • Core 包含了语言“内置”的所有功能。
  • Base 包含了绝大多数情况下都会用到的基本功能。
  • Main 是顶层模块,当 julia 启动时,也是当前模块。

元编程

程序表示

每个 Julia 程序均以字符串开始:

julia> prog = "1 + 1"
"1 + 1"

julia> ex1 = Meta.parse(prog)
:(1 + 1)
# 也可以显式地用:(<Julia语句>)的方式构造表达式

# 表达式类型
julia> typeof(ex1)
Expr

# 计算
julia> eval(ex1)
2

Expr 对象包含两个部分:

  • 一个标识表达式类型的 Symbol。(Symbol 就是一个 interned string 标识符)
julia> ex1.head
:call
  • 表达式的参数,可能是符号、其他表达式或字面值:
julia> ex1.args
3-element Array{Any,1}:
  :+
 1
 1

表达式也可以直接用 prefix notation 构造:

julia> ex2 = Expr(:call, :+, 1, 1)
:(1 + 1)

这里的关键点是 Julia 的代码在内部表示为可以从语言本身访问的数据结构

函数 dump 可以带有缩进和注释地显示 Expr 对象:

julia> dump(ex2)
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Int64 1
    3: Int64 1

Expr 对象也可以嵌套:

julia> ex3 = Meta.parse("(4 + 4) / 2")
:((4 + 4) / 2)

julia> dump(ex3)
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol /
    2: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol +
        2: Int64 4
        3: Int64 4
    3: Int64 2

多行表达式Quote

多行表达式可以在quote … end中实现

ex4 = quote
	x = 1
	y = 2
	x + y
end

插值

Julia 允许将字面量或表达式插入到被引用的表达式中。表达式插值由前缀 $ 表示。

julia> a = 1;

julia> ex = :($a + b)
:(1 + b)

关于表达式的函数

Julia 能在其内部生成和操作 Julia 代码

julia> function math_expr(op, op1, op2)
           expr = Expr(:call, op, op1, op2)
           return expr
       end
math_expr (generic function with 1 method)

julia>  ex = math_expr(:+, 1, Expr(:call, :*, 4, 5))
:(1 + 4 * 5)

julia> eval(ex)
21

作为另一个例子,这个函数将数值参数加倍,但不处理表达式:

julia> function make_expr2(op, opr1, opr2)
           opr1f, opr2f = map(x -> isa(x, Number) ? 2*x : x, (opr1, opr2))
           retexpr = Expr(:call, op, opr1f, opr2f)
           return retexpr
       end
make_expr2 (generic function with 1 method)

julia> make_expr2(:+, 1, 2)
:(2 + 4)

julia> ex = make_expr2(:+, 1, Expr(:call, :*, 5, 8))
:(2 + 5 * 8)

基础

宏提供了在程序的最终主体中包含所生成的代码的方法。宏将参数元组映射到所返回的表达式,且生成的表达式会被直接编译,并不需要运行时的 eval 调用。宏的参数可以包括表达式、字面量值和符号。

这是一个非常简单的宏:

julia> macro sayhello()
           return :( println("Hello, world!") )
       end
@sayhello (macro with 1 method)

宏在Julia的语法中有一个专门的字符 @ 。紧接着是其使用macro NAME … end 形式来声明的唯一的宏名。在这个例子中,编译器会把所有的@sayhello 替换成:

:( println("Hello, world!") )

当 @sayhello 在REPL中被输入时,解释器立即执行,因此我们只会看到计算后的结果。

现在,考虑一个稍微复杂一点的宏:

julia> macro sayhello(name)
 return :( println("Hello, ", $name) )
 end
@sayhello (macro with 1 method)

这个宏接受一个参数name。当遇到@sayhello时,quoted 表达式会被展开并将参数中的值插入到最终的表达式中:

julia> @sayhello("human")
Hello, human

宏的调用

@name expr1 expr2 ...
@name(expr1, expr2, ...)

在宏名称前的标志 @,且在第一种形式中参数表达式间没有逗号,而在第二种形式中 @name 后没有空格。这两种风格不应混淆。

宏把它们的参数作为表达式、字面量或符号接收。浏览宏参数的一种方法是在宏的内部调用 show 函数:

julia> macro showarg(x)
           show(x)
           # ... remainder of macro, returning an expression
       end
@showarg (macro with 1 method)

julia> @showarg(a)
:a

julia> @showarg(1+1)
:(1 + 1)

julia> @showarg(println("Yo!"))
:(println("Yo!"))

构建高级的宏

Julia @assert宏:

julia> macro assert(ex)
           return :( $ex ? nothing : throw(AssertionError($(string(ex)))) )
       end
@assert (macro with 1 method)

使用:

julia> @assert 1 == 1.0

julia> @assert 1 == 0
ERROR: AssertionError: 1 == 0

常用宏

@time 计算程序运行时间
@which 语句调用位置
@show 显示执行内容和结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值