文档

访问文档

可以在 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) ...

与上面的示例一样,我们建议在编写文档时遵循一些简单的约定

  1. 始终在文档顶部显示函数签名,并使用四个空格缩进,以便将其打印为 Julia 代码。

    这可以与 Julia 代码中存在的签名相同(如 mean(x::AbstractArray)),也可以是简化的形式。可选参数应尽可能用其默认值表示(即 f(x, y=1)),遵循实际的 Julia 语法。没有默认值的可选参数应放在方括号中(即 f(x[, y])f(x[, y[, z]]))。另一种解决方案是使用多行:一行不带可选参数,另一行带可选参数。这种解决方案也可以用来记录给定函数的几个相关方法。当函数接受许多关键字参数时,在签名中只包含一个 <关键字参数> 占位符(即 f(x; <关键字参数>)),并在 # 参数 部分给出完整列表(见下面的第 4 点)。

  2. 在简化的签名块之后,包括一个单行句子描述函数的作用或对象所代表的内容。如果需要,在空行之后,在第二段中提供更多细节。

    单行句子应使用祈使句(“这样做”、“返回那个”)而不是第三人称(不要写“返回长度...”)来记录函数。它应该以句号结束。如果函数的含义无法轻松概括,将其拆分为独立的可组合部分可能会有益(但这不应该被视为对每个单独情况的绝对要求)。

  3. 不要重复自己。

    由于函数名由签名给出,因此无需以“函数 bar...”开头文档:直接切入主题。类似地,如果签名指定了参数的类型,那么在描述中提及它们就是多余的。

  4. 只有在真正需要时才提供参数列表。

    对于简单的函数,在函数目的的描述中直接提及参数的作用往往更清晰。参数列表只会重复在其他地方提供的信息。但是,对于具有许多参数(特别是关键字参数)的复杂函数,提供参数列表可能是一个好主意。在这种情况下,将其插入函数的总体描述之后,在 # 参数 标题下,每个参数用一个 - 项目符号表示。列表应该提到参数的类型和默认值(如果有)。

    """
    ...
    # Arguments
    - `n::Integer`: the number of elements to compute.
    - `dim::Integer=1`: the dimensions along which to perform the computation.
    ...
    """
  5. 提供相关函数的提示。

    有时会有功能相关的函数。为了提高可发现性,请在 另请参阅 段落中提供这些函数的简短列表。

    See also [`bar!`](@ref), [`baz`](@ref), [`baaz`](@ref).
  6. # 示例 部分中包含任何代码示例。

    示例应尽可能地写成doctestdoctest 是一个以 ```jldoctest 开头的代码围栏块(见 代码块),包含任意数量的 julia> 提示以及模拟 Julia REPL 的输入和预期输出。

    注意

    doctestDocumenter.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
    ```
    """
    警告

    doctest 中应避免调用 rand 和其他与 RNG 相关的函数,因为它们在不同的 Julia 会话期间不会产生一致的输出。如果您想展示一些与随机数生成相关的功能,一种方法是显式地构造并播种自己的 RNG 对象(见 Random),并将它传递给您正在测试的函数。

    操作系统字长 (Int32Int64) 以及路径分隔符差异 (/\) 也会影响一些 doctest 的可重复性。

    请注意,doctest 中的空白字符很重要!例如,如果您错误地对数组的漂亮打印输出进行对齐,doctest 将会失败。

    然后,您可以运行 make -C doc doctest=true 来运行 Julia 手册和 API 文档中的所有 doctest,这将确保您的示例有效。

    要指示输出结果被截断,您可以在应停止检查的行中写入 [...]。例如,当 doctest 显示抛出异常时,这对于隐藏堆栈跟踪(包含对 Julia 代码行的非永久性引用)很有用。

    ```jldoctest
    julia> div(1, 0)
    ERROR: DivideError: integer division error
    [...]
    ```

    不可测试的示例应写入以 ```julia 开头的代码围栏块中,以便它们在生成的文档中正确突出显示。

    提示

    只要有可能,示例都应该是自包含可运行的,以便读者能够尝试它们,而无需包含任何依赖项。

  7. 使用反引号标识代码和方程式。

    Julia 标识符和代码片段应始终出现在反引号 ` 之间以启用突出显示。 LaTeX 语法的方程式可以插入双反引号 `` 之间。 使用 Unicode 字符而不是它们的 LaTeX 转义序列,例如 ``α = 1`` 而不是 ``\\alpha = 1``。

  8. 将起始和结束 """ 字符单独放在一行上。

    也就是说,写

    """
    ...
    
    ...
    """
    f(x, y) = ...

    而不是

    """...
    
    ..."""
    f(x, y) = ...

    这样可以更清楚地表明文档字符串的开始和结束位置。

  9. 遵守周围代码中使用的行长限制。

    文档字符串使用与代码相同的工具进行编辑。 因此,应使用相同的约定。 建议行宽不超过 92 个字符。

  10. 在 # Implementation 部分提供信息,允许自定义类型在其中实现函数。 这些实现细节旨在供开发人员而非用户使用,例如解释应重写哪些函数以及哪些函数会自动使用适当的回退。 此类细节最好与函数行为的主要描述分开。

  11. 对于较长的文档字符串,请考虑使用 # 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__ 在使用它的宏没有被记录时没有效果。

来源