文档
访问文档
可以在 REPL 或 IJulia 中访问文档,方法是键入 ?
后跟函数或宏的名称,然后按 Enter
键。例如,
?cos
?@time
?r""
将分别显示相关函数、宏或字符串宏的文档。大多数 Julia 环境都提供了一种直接访问文档的方法
- VS Code 在您将鼠标悬停在函数名称上时会显示文档。您也可以使用侧边栏中的 Julia 面板搜索文档。
- 在 Pluto 中,打开右下角的“实时文档”面板。
- 在 Juno 中,使用
Ctrl-J, Ctrl-D
将显示光标下对象的文档。
编写文档
Julia 使得包开发者和用户可以通过内置文档系统轻松地为函数、类型和其他对象编写文档。
基本语法很简单:出现在对象(函数、宏、类型或实例)之前的任何字符串都将被解释为对其进行文档化(这些称为docstring)。请注意,在 docstring 和已文档化的对象之间不能有空行或注释。以下是一个基本示例
"Tell whether there are too foo items in the array."
foo(xs::Array) = ...
文档被解释为 Markdown,因此您可以使用缩进和代码围栏将代码示例与文本区分开来。从技术上讲,任何对象都可以作为元数据与任何其他对象相关联;Markdown 恰好是默认值,但也可以构建其他字符串宏并将它们传递给 @doc
宏。
Markdown 支持在 Markdown
标准库中实现,有关支持的语法完整列表,请参阅 文档。
以下是一个更复杂的示例,仍然使用 Markdown
"""
bar(x[, y])
Compute the Bar index between `x` and `y`.
If `y` is unspecified, compute the Bar index between all pairs of columns of `x`.
# Examples
```julia-repl
julia> bar([1, 2], [1, 2])
1
```
"""
function bar(x, y) ...
与上面的示例一样,我们建议在编写文档时遵循一些简单的约定
始终在文档顶部显示函数签名,并使用四个空格缩进,以便将其打印为 Julia 代码。
这可以与 Julia 代码中存在的签名相同(如
mean(x::AbstractArray)
),也可以是简化的形式。可选参数应尽可能用其默认值表示(即f(x, y=1)
),遵循实际的 Julia 语法。没有默认值的可选参数应放在方括号中(即f(x[, y])
和f(x[, y[, z]])
)。另一种解决方案是使用多行:一行不带可选参数,另一行带可选参数。这种解决方案也可以用来记录给定函数的几个相关方法。当函数接受许多关键字参数时,在签名中只包含一个<关键字参数>
占位符(即f(x; <关键字参数>)
),并在# 参数
部分给出完整列表(见下面的第 4 点)。在简化的签名块之后,包括一个单行句子描述函数的作用或对象所代表的内容。如果需要,在空行之后,在第二段中提供更多细节。
单行句子应使用祈使句(“这样做”、“返回那个”)而不是第三人称(不要写“返回长度...”)来记录函数。它应该以句号结束。如果函数的含义无法轻松概括,将其拆分为独立的可组合部分可能会有益(但这不应该被视为对每个单独情况的绝对要求)。
不要重复自己。
由于函数名由签名给出,因此无需以“函数
bar
...”开头文档:直接切入主题。类似地,如果签名指定了参数的类型,那么在描述中提及它们就是多余的。只有在真正需要时才提供参数列表。
对于简单的函数,在函数目的的描述中直接提及参数的作用往往更清晰。参数列表只会重复在其他地方提供的信息。但是,对于具有许多参数(特别是关键字参数)的复杂函数,提供参数列表可能是一个好主意。在这种情况下,将其插入函数的总体描述之后,在
# 参数
标题下,每个参数用一个-
项目符号表示。列表应该提到参数的类型和默认值(如果有)。""" ... # Arguments - `n::Integer`: the number of elements to compute. - `dim::Integer=1`: the dimensions along which to perform the computation. ... """
提供相关函数的提示。
有时会有功能相关的函数。为了提高可发现性,请在
另请参阅
段落中提供这些函数的简短列表。See also [`bar!`](@ref), [`baz`](@ref), [`baaz`](@ref).
在
# 示例
部分中包含任何代码示例。示例应尽可能地写成doctest。doctest 是一个以
```jldoctest
开头的代码围栏块(见 代码块),包含任意数量的julia>
提示以及模拟 Julia REPL 的输入和预期输出。注意 doctest 由
Documenter.jl
启用。有关更详细的文档,请参阅 Documenter 的 手册。例如,在以下 docstring 中,定义了一个变量
a
,并在之后显示了预期结果(如 Julia REPL 中打印的那样)""" Some nice documentation here. # Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: 1 2 3 4 ``` """
警告 然后,您可以运行
make -C doc doctest=true
来运行 Julia 手册和 API 文档中的所有 doctest,这将确保您的示例有效。要指示输出结果被截断,您可以在应停止检查的行中写入
[...]
。例如,当 doctest 显示抛出异常时,这对于隐藏堆栈跟踪(包含对 Julia 代码行的非永久性引用)很有用。```jldoctest julia> div(1, 0) ERROR: DivideError: integer division error [...] ```
不可测试的示例应写入以
```julia
开头的代码围栏块中,以便它们在生成的文档中正确突出显示。提示 只要有可能,示例都应该是自包含和可运行的,以便读者能够尝试它们,而无需包含任何依赖项。
使用反引号标识代码和方程式。
Julia 标识符和代码片段应始终出现在反引号 ` 之间以启用突出显示。 LaTeX 语法的方程式可以插入双反引号 `` 之间。 使用 Unicode 字符而不是它们的 LaTeX 转义序列,例如 ``α = 1`` 而不是 ``\\alpha = 1``。
将起始和结束 """ 字符单独放在一行上。
也就是说,写
""" ... ... """ f(x, y) = ...
而不是
"""... ...""" f(x, y) = ...
这样可以更清楚地表明文档字符串的开始和结束位置。
遵守周围代码中使用的行长限制。
文档字符串使用与代码相同的工具进行编辑。 因此,应使用相同的约定。 建议行宽不超过 92 个字符。
在 # Implementation 部分提供信息,允许自定义类型在其中实现函数。 这些实现细节旨在供开发人员而非用户使用,例如解释应重写哪些函数以及哪些函数会自动使用适当的回退。 此类细节最好与函数行为的主要描述分开。
对于较长的文档字符串,请考虑使用 # Extended help 标题将文档拆分。 典型帮助模式将只显示标题以上的内容; 可以在表达式开头添加“?”以访问完整帮助(即“??foo”而不是“?foo”)。
函数和方法
Julia 中的函数可能有多种实现,称为方法。 虽然通用函数有一个用途是一个好习惯,但 Julia 允许在必要时单独记录方法。 通常,只有最通用的方法应该被记录,甚至函数本身(即,由 function bar end 创建的对象)。 只有在特定方法的行为与更通用方法的行为不同时,才应记录特定方法。 无论如何,它们都不应重复其他地方提供的信息。 例如
"""
*(x, y, z...)
Multiplication operator. `x * y * z *...` calls this function with multiple
arguments, i.e. `*(x, y, z...)`.
"""
function *(x, y, z...)
# ... [implementation sold separately] ...
end
"""
*(x::AbstractString, y::AbstractString, z::AbstractString...)
When applied to strings, concatenates them.
"""
function *(x::AbstractString, y::AbstractString, z::AbstractString...)
# ... [insert secret sauce here] ...
end
help?> *
search: * .*
*(x, y, z...)
Multiplication operator. x * y * z *... calls this function with multiple
arguments, i.e. *(x,y,z...).
*(x::AbstractString, y::AbstractString, z::AbstractString...)
When applied to strings, concatenates them.
检索通用函数的文档时,将使用 catdoc 函数将每个方法的元数据连接起来,当然,catdoc 函数可以为自定义类型重写。
高级用法
@doc 宏将其第一个参数与其第二个参数关联在一个称为 META 的每个模块字典中。
为了便于编写文档,解析器对宏名称 @doc 进行特殊处理:如果对 @doc 的调用有一个参数,但在单个换行符之后出现另一个表达式,则该附加表达式将作为参数添加到宏中。 因此,以下语法被解析为对 @doc 的 2 个参数调用
@doc raw"""
...
"""
f(x) = x
这使得可以使用除普通字符串文字(如 raw"" 字符串宏)以外的表达式作为文档字符串。
在用于检索文档时,@doc 宏(或同等地,doc 函数)将搜索所有 META 字典以查找与给定对象相关的元数据并返回它。 返回的对象(例如一些 Markdown 内容)默认情况下会智能地显示自己。 此设计还使得以编程方式轻松使用文档系统; 例如,在函数的不同版本之间重复使用文档
@doc "..." foo!
@doc (@doc foo!) foo
或与 Julia 的元编程功能一起使用
for (f, op) in ((:add, :+), (:subtract, :-), (:multiply, :*), (:divide, :/))
@eval begin
$f(a,b) = $op(a,b)
end
end
@doc "`add(a,b)` adds `a` and `b` together" add
@doc "`subtract(a,b)` subtracts `b` from `a`" subtract
非顶层块(如 begin、if、for 和 let)中的文档也应通过 @doc 添加到文档系统中。 例如
if condition()
@doc "..."
f(x) = x
end
当 condition() 为 true 时,将向 f(x) 添加文档。 请注意,即使 f(x) 在块结束时超出范围,其文档也将保留。
可以使用元编程来辅助文档的创建。 在文档字符串中使用字符串插值时,需要使用额外的 $,如 $($name) 所示
for func in (:day, :dayofmonth)
name = string(func)
@eval begin
@doc """
$($name)(dt::TimeType) -> Int64
The day of month of a `Date` or `DateTime` as an `Int64`.
""" $func(dt::Dates.TimeType)
end
end
动态文档
有时,类型实例的适当文档取决于该实例的字段值,而不仅仅取决于类型本身。 在这些情况下,可以为自定义类型添加 Docs.getdoc 的方法,该方法根据每个实例返回文档。 例如,
struct MyType
value::Int
end
Docs.getdoc(t::MyType) = "Documentation for MyType with value $(t.value)"
x = MyType(1)
y = MyType(2)
?x 将显示“具有值 1 的 MyType 的文档”,而 ?y 将显示“具有值 2 的 MyType 的文档”。
语法指南
本指南全面概述了如何将文档附加到所有可能提供文档的 Julia 语法结构。
在以下示例中,"..." 用于说明任意文档字符串。
$ 和 \
字符
$ 和 \ 字符在文档字符串中仍被解析为字符串插值或转义序列的开始。 raw"" 字符串宏与 @doc 宏一起使用可以避免必须转义它们。 这在文档字符串包含包含插值的 LaTeX 或 Julia 源代码示例时非常有用
@doc raw"""
```math
\LaTeX
```
"""
function f end
函数和方法
"..."
function f end
"..."
f
将文档字符串 "..." 添加到函数 f 中。 第一个版本是首选语法,但两者都等效。
"..."
f(x) = x
"..."
function f(x)
x
end
"..."
f(x)
将文档字符串 "..." 添加到方法 f(::Any) 中。
"..."
f(x, y = 1) = x + y
将文档字符串 "..." 添加到两个 Method 中,即 f(::Any) 和 f(::Any, ::Any)。
宏
"..."
macro m(x) end
将文档字符串 "..." 添加到 @m(::Any) 宏定义中。
"..."
:(@m)
将文档字符串 "..." 添加到名为 @m 的宏中。
类型
"..."
abstract type T1 end
"..."
mutable struct T2
...
end
"..."
struct T3
...
end
将文档字符串 "..." 添加到类型 T1、T2 和 T3 中。
"..."
struct T
"x"
x
"y"
y
end
将文档字符串 "..." 添加到类型 T 中,"x" 添加到字段 T.x 中,"y" 添加到字段 T.y 中。 也适用于 mutable struct 类型。
模块
"..."
module M end
module M
"..."
M
end
将文档字符串 "..." 添加到 Module M 中。 在 Module 以上添加文档字符串是首选语法,但两者都等效。
"..."
baremodule M
# ...
end
baremodule M
import Base: @doc
"..."
f(x) = x
end
通过在表达式上方放置文档字符串来记录 baremodule 会自动将 @doc 导入模块。 当模块表达式没有被记录时,必须手动进行这些导入。
全局变量
"..."
const a = 1
"..."
b = 2
"..."
global c = 3
将文档字符串 "..." 添加到 Binding a、b 和 c 中。
Binding 用于在 Module 中存储对特定 Symbol 的引用,而不存储引用的值本身。
当 const 定义仅用于定义另一个定义的别名时,例如 Base 中的函数 div 及其别名 ÷ 的情况,请不要记录别名,而是记录实际函数。
如果记录了别名但没有记录实际定义,那么当搜索实际定义时,文档系统(? 模式)将不会返回附加到别名的文档字符串。
例如,您应该编写
"..."
f(x) = x + 1
const alias = f
而不是
f(x) = x + 1
"..."
const alias = f
"..."
sym
将文档字符串 "..." 添加到与 sym 关联的值中。 但是,最好在 sym 定义的位置记录它。
多个对象
"..."
a, b
将文档字符串 "..." 添加到 a 和 b 中,它们都应该是可记录的表达式。 此语法等效于
"..."
a
"..."
b
可以以这种方式一起记录任意数量的表达式。 当两个函数相关时,此语法很有用,例如非变异和变异版本 f 和 f!。
宏生成的代码
"..."
@m expression
将文档字符串 "..." 添加到展开 @m expression 生成的表达式中。 这允许使用 @inline、@noinline、@generated 或任何其他宏修饰的表达式以与未修饰表达式相同的方式记录。
宏作者应注意,只有生成单个表达式的宏才会自动支持文档字符串。 如果宏返回包含多个子表达式的块,则应使用 @__doc__
宏标记应记录的子表达式。
@enum
宏使用 @__doc__
来允许记录 Enum
。 检查其定义应该作为如何正确使用 @__doc__
的示例。
Core.@__doc__
— 宏@__doc__(ex)
用于标记宏返回的应记录的表达式的低级宏。 如果标记了多个表达式,则相同的文档字符串将应用于每个表达式。
macro example(f)
quote
$(f)() = 0
@__doc__ $(f)(x) = 1
$(f)(x, y) = 2
end |> esc
end
@__doc__
在使用它的宏没有被记录时没有效果。