反射 与 自我检查

    导出的名称使用 names(m::Module) ,会返回一个由 元素组成的数组,表示导出的绑定。 不管导出状态如何,names(m::Module, all = true) 返回 m 中所有绑定的符号。

    数据类型字段

    数据类型 的所有字段名称可以使用 来获取。 例如下面给定一个类型,fieldnames(Point) 会返回一个表示字段名称的 关于 Symbol 的元组

    Point 对象中的每个字段的类型 存储在 Point 本身的 types 变量中。

    1. julia> Point.types
    2. svec(Int64, Any)

    不过x 被声明为 Int,而 y 未声明类型,因此y 默认为 Any 类型。

    类型本身表示为一个叫做 DataType 的结构:

    任何 的 直接 子类型 都可以通过使用 来列出。 例如 抽象类型 DataType AbstractFloat 有四个(具体的)子类型:

    1. julia> subtypes(AbstractFloat)
    2. 4-element Array{Any,1}:
    3. BigFloat
    4. Float16
    5. Float64

    Any abstract subtype will also be included in this list, but further subtypes thereof will not; 任何抽象的子类型也会被包括其中,但不会有更深的子类型。 的递归使用可以检查出整个类型树

    数据类型布局设计

    用 C 代码接口时,DataType 的内部表现非常重要。有几个函数可以检查这些细节。

    如果 T 类型是以 C 兼容的对齐方式存储,则为 true。 fieldoffset(T::DataType, i::Integer) 返回字段 i 相对于类型开始的 (字节) 偏移量。

    任何泛型函数的方法都可以使用 来列出。用 methodswith 搜索 方法调度表 来查找 接收给定类型的方法。

    扩展和更底层

    函数 Base.Meta.show_sexprdump 用来展示 S-表达式样式预览 并且对任何表达式显示深层网络结构细节。

    最终, 函数对任何表达式提供 底层 的形式,并且是令人感兴趣的是理解 语言的结构 映射到 原始的操作比如赋值、分支以及调用:

    1. julia> Meta.lower(@__MODULE__, :([1+2, sin(0.5)]) )
    2. :($(Expr(:thunk, CodeInfo(
    3. 1 %1 = 1 + 2
    4. %2 = sin(0.5)
    5. %3 = (Base.vect)(%1, %2)
    6. ))))

    检查函数的底层形式 需要选择所要显示的特定方法,因为泛型函数可能会有许多具有不同类型签名的方法。为此, 用 code_lowered 可以指定代码底层中的方法。 并且可以用 来进行类型推断。 code_warntype 增加 输出的高亮。

    更加接近于机器, 一个函数的 LLVM-IR 可以通过使用 code_llvm 打印出。 最终编译的机器码使用 查看(这将触发 之前未调用过的任何函数的 JIT 编译/代码生成)。

    为方便起见,上述函数有 宏的版本,它们接受标准函数调用并自动展开参数类型: