owned this note
owned this note
Published
Linked with GitHub
# Reflection and introspection
Julia提供了多樣的runtime reflection能力。
## 模組綁定
The exported names for a `Module` are available using [`names(m::Module)`](@ref), which will return
an array of [`Symbol`](@ref) elements representing the exported bindings. `names(m::Module, true)`
returns symbols for all bindings in `m`, regardless of export status.
## DataType fields
`DataType`的field names可以使用[`fieldnames()`](@ref)來查詢. 舉例來說,如果有以下型別,`fieldnames(Point)`會回傳一個裝有[`Symbol`](@ref)的陣列來代表field names:
```julia
julia> struct Point
x::Int
y
end
julia> fieldnames(Point)
2-element Array{Symbol,1}:
:x
:y
```
`Point`物件中每個field的型別是儲存於`Point`變數的`types` field中:
```julia
julia> Point.types
svec(Int64,Any)
```
`x`被標記為`Int`,`y`則不被標記任何型別定義,因此`y`會預設為`Any`型別。
型別他們自身表示為一個稱為`DataType`的結構:
```julia
julia> typeof(Point)
DataType
```
`fieldnames(DataType)`則會給出`DataType`的每個field自身的名稱,這些fields當中有一個是`types` field,就如同上例觀察到的一樣。
## 子型別
The *direct* subtypes of any `DataType` may be listed using [`subtypes()`](@ref). For example,
the abstract `DataType``AbstractFloat` has four (concrete) subtypes:
```julia
julia> subtypes(AbstractFloat)
4-element Array{DataType,1}:
BigFloat
Float16
Float32
Float64
```
Any abstract subtype will also be included in this list, but further subtypes thereof will not;
recursive application of [`subtypes()`](@ref) may be used to inspect the full type tree.
## DataType layout
The internal representation of a `DataType` is critically important when interfacing with C code
and several functions are available to inspect these details. [`isbits(T::DataType)`](@ref) returns
true if `T` is stored with C-compatible alignment. [`fieldoffset(T::DataType, i::Integer)`](@ref)
returns the (byte) offset for field *i* relative to the start of the type.
## 函式的方法
可以利用[`methods()`](@ref)列出任何泛型函式的方法。 可以用[`methodswith()`](@ref)來查方法分派表,來得到接受給定型別參數的方法。
## 擴張與lowering
如同在[Metaprogramming](@ref)探討過的,[`macroexpand()`](@ref)函式會對給定的macro給出unquoted且已經內插的表達式 (`Expr`)。 使用`macroexpand`,要將表達式用`quote`包住 (除非macro會被求值且回傳結果!)。舉例來說:
```julia
julia> macroexpand( :(@edit println("")) )
:((Base.edit)(println,(Base.typesof)("")))
```
`Base.Meta.show_sexpr()`跟[`dump()`](@ref)可以用來顯示任何表達式的S-expr style views跟depth-nested detail views。
最後,[`expand()`](@ref)會給出任何表達式的`lowered` form,而且他也是想了解macro與高階陳述,像是函式宣告跟指定變數,的大家會特別感興趣的部份:
```julia
julia> expand( :(f() = 1) )
:(begin
$(Expr(:method, :f))
$(Expr(:method, :f, :((Core.svec)((Core.svec)((Core.Typeof)(f)),(Core.svec)())), CodeInfo(:(begin # none, line 1:
return 1
end)), false))
return f
end)
```
## 中間表示與編譯後表示
檢查函式lowered form需要選擇特定方法來顯示,因為泛型函式可能有非常多接受不同型別的方法。為了這個目的,特定方法的程式碼lowering可以用 [`code_lowered(f::Function, (Argtypes...))`](@ref)得到,而type-inferred form則可以用[`code_typed(f::Function, (Argtypes...))`](@ref)。
[`code_warntype(f::Function, (Argtypes...))`](@ref)會強調型別到[`code_typed()`](@ref)的輸出上(見[`@code_warntype`](@ref))。
更接近機器端,函式的LLVM中介碼可以用[`code_llvm(f::Function, (Argtypes...))`](@ref)印出,接著,最後編譯過的機器碼可以用[`code_native(f::Function, (Argtypes...))`](@ref)(任何沒有被呼叫過的函式會觸發JIT compilation/code generation)。
為了方便,以上的函式都有macro版本,他們會自動執行標準的函式呼叫跟擴張參數型別:
```julia
julia> @code_llvm +(1,1)
; Function Attrs: sspreq
define i64 @"julia_+_130862"(i64, i64) #0 {
top:
%2 = add i64 %1, %0, !dbg !8
ret i64 %2, !dbg !8
}
```
(`@code_typed`、`@code_warntype`、`@code_lowered`跟`@code_native`使用方法相同)