From a2a1bb7c18cb99824c6ca9d8d9183a9388961d01 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Tue, 16 Jun 2020 18:58:27 +0800 Subject: [PATCH 1/4] Sync 1.4 --- zh_CN/doc/src/manual/arrays.md | 154 +++++++++++++----- .../src/manual/calling-c-and-fortran-code.md | 6 +- zh_CN/doc/src/manual/constructors.md | 47 ++++-- zh_CN/doc/src/manual/control-flow.md | 14 +- .../src/manual/conversion-and-promotion.md | 3 +- zh_CN/doc/src/manual/documentation.md | 4 +- zh_CN/doc/src/manual/faq.md | 67 +++++++- zh_CN/doc/src/manual/functions.md | 54 +++++- .../integers-and-floating-point-numbers.md | 15 +- zh_CN/doc/src/manual/interfaces.md | 24 +-- .../doc/src/manual/mathematical-operations.md | 6 +- zh_CN/doc/src/manual/metaprogramming.md | 42 +++-- .../doc/src/manual/noteworthy-differences.md | 9 +- zh_CN/doc/src/manual/parallel-computing.md | 39 ++++- zh_CN/doc/src/manual/performance-tips.md | 71 +++++++- .../src/manual/running-external-programs.md | 2 +- zh_CN/doc/src/manual/stacktraces.md | 1 - zh_CN/doc/src/manual/strings.md | 33 ++-- zh_CN/doc/src/manual/style-guide.md | 4 +- zh_CN/doc/src/manual/types.md | 12 +- zh_CN/doc/src/manual/variables-and-scoping.md | 10 +- zh_CN/doc/src/manual/variables.md | 2 +- 22 files changed, 483 insertions(+), 136 deletions(-) diff --git a/zh_CN/doc/src/manual/arrays.md b/zh_CN/doc/src/manual/arrays.md index 81708dc0..8a929f4b 100644 --- a/zh_CN/doc/src/manual/arrays.md +++ b/zh_CN/doc/src/manual/arrays.md @@ -42,16 +42,14 @@ Julia 提供了许多用于构造和初始化数组的函数。在下列函数 | [`reinterpret(T, A)`](@ref) | 与 `A` 具有相同二进制数据的数组,但元素类型为 `T` | | [`rand(T, dims...)`](@ref) | 一个随机 `Array`,元素值是 ``[0, 1)`` 半开区间中的均匀分布且服从一阶独立同分布 [^1] | | [`randn(T, dims...)`](@ref) | 一个随机 `Array`,元素为标准正态分布,服从独立同分布 | -| [`Matrix{T}(I, m, n)`](@ref) | `m` 行 `n` 列的单位矩阵 | +| [`Matrix{T}(I, m, n)`](@ref) | `m`-by-`n` identity matrix (requires `using LinearAlgebra`) | | [`range(start, stop=stop, length=n)`](@ref) | 从 `start` 到 `stop` 的带有 `n` 个线性间隔元素的范围 | | [`fill!(A, x)`](@ref) | 用值 `x` 填充数组 `A` | | [`fill(x, dims...)`](@ref) | 一个被值 `x` 填充的 `Array` | [^1]: *iid*,独立同分布 -用 `[A,B,C,...]` 来构造 1 维数组(即为向量)。如果所有参数有一个共同的提升类型([promotion type](@ref conversion-and-promotion)),那么它们会被 [`convert`](@ref) 函数转换为该类型。 - -要查看各种方法,我们可以将不同维数传递给这些构造函数,请考虑以下示例: +To see the various ways we can pass dimensions to these functions, consider the following examples: ```jldoctest julia> zeros(Int8, 2, 3) 2×3 Array{Int8,2}: @@ -68,60 +66,125 @@ julia> zeros((2, 3)) 0.0 0.0 0.0 0.0 0.0 0.0 ``` -这里的 `(2, 3)` 是一个 [`Tuple`](@ref)。 - -## 拼接 +Here, `(2, 3)` is a [`Tuple`](@ref) and the first argument — the element type — is optional, defaulting to `Float64`. -可以使用以下函数构造和拼接数组: +## [Array literals](@id man-array-literals) -| 函数 | 描述 | -|:--------------------------- |:----------------------------------------------- | -| [`cat(A...; dims=k)`](@ref) | 沿着 s 的第 `k` 维拼接数组 | -| [`vcat(A...)`](@ref) | `cat(A...; dims=1)` 的简写 | -| [`hcat(A...)`](@ref) | `cat(A...; dims=2)` 的简写 | +Arrays can also be directly constructed with square braces; the syntax `[A, B, C, ...]` +creates a one dimensional array (i.e., a vector) containing the comma-separated arguments as +its elements. The element type ([`eltype`](@ref)) of the resulting array is automatically +determined by the types of the arguments inside the braces. If all the arguments are the +same type, then that is its `eltype`. If they all have a common +[promotion type](@ref conversion-and-promotion) then they get converted to that type using +[`convert`](@ref) and that type is the array's `eltype`. Otherwise, a heterogeneous array +that can hold anything — a `Vector{Any}` — is constructed; this includes the literal `[]` +where no arguments are given. -传递给这些函数的标量值会被当作单元素数组。例如, ```jldoctest -julia> vcat([1, 2], 3) +julia> [1,2,3] # An array of `Int`s 3-element Array{Int64,1}: 1 2 3 -julia> hcat([1 2], 3) -1×3 Array{Int64,2}: - 1 2 3 +julia> promote(1, 2.3, 4//5) # This combination of Int, Float64 and Rational promotes to Float64 +(1.0, 2.3, 0.8) + +julia> [1, 2.3, 4//5] # Thus that's the element type of this Array +3-element Array{Float64,1}: + 1.0 + 2.3 + 0.8 + +julia> [] +0-element Array{Any,1} ``` -这些拼接函数非常常用,因此它们有特殊的语法: +### [Concatenation](@id man-array-concatenation) -| 表达式 | 调用 | -|:----------------- |:----------------- | -| `[A; B; C; ...]` | [`vcat`](@ref) | -| `[A B C ...]` | [`hcat`](@ref) | -| `[A B; C D; ...]` | [`hvcat`](@ref) | +If the arguments inside the square brackets are separated by semicolons (`;`) or newlines +instead of commas, then their contents are _vertically concatenated_ together instead of +the arguments being used as elements themselves. -[`hvcat`](@ref) 可以在第 1 维列数组(用分号分隔)和第 2 维行数组(用空格分隔)进行拼接。 -请考虑以下语法示例: ```jldoctest -julia> [[1; 2]; [3, 4]] +julia> [1:2, 4:5] # Has a comma, so no concatenation occurs. The ranges are themselves the elements +2-element Array{UnitRange{Int64},1}: + 1:2 + 4:5 + +julia> [1:2; 4:5] 4-element Array{Int64,1}: 1 2 - 3 4 + 5 -julia> [[1 2] [3 4]] -1×4 Array{Int64,2}: - 1 2 3 4 +julia> [1:2; 4:5] +4-element Array{Int64,1}: + 1 + 2 + 4 + 5 -julia> [[1 2]; [3 4]] +julia> [1:2 + 4:5 + 6] +5-element Array{Int64,1}: + 1 + 2 + 4 + 5 + 6 +``` + +Similarly, if the arguments are separated by tabs or spaces, then their contents are +_horizontally concatenated_ together. + +```jldoctest +julia> [1:2 4:5 7:8] +2×3 Array{Int64,2}: + 1 4 7 + 2 5 8 + +julia> [[1,2] [4,5] [7,8]] +2×3 Array{Int64,2}: + 1 4 7 + 2 5 8 + +julia> [1 2 3] # Numbers can also be horizontally concatenated +1×3 Array{Int64,2}: + 1 2 3 +``` + +Using semicolons (or newlines) and spaces (or tabs) can be combined to concatenate +both horizontally and vertically at the same time. + +```jldoctest +julia> [1 2 + 3 4] 2×2 Array{Int64,2}: 1 2 3 4 + +julia> [zeros(Int, 2, 2) [1; 2] + [3 4] 5] +3×3 Array{Int64,2}: + 0 0 1 + 0 0 2 + 3 4 5 ``` -## 限定类型数组的初始化 +More generally, concatenation can be accomplished through the [`cat`](@ref) function. +These syntaxes are shorthands for function calls that themselves are convenience functions: + +| 语法 | 函数 | 描述 | +|:----------------- |:--------------- |:-------------------------------------------------- | +| | [`cat`](@ref) | 沿着 s 的第 `k` 维拼接数组 | +| `[A; B; C; ...]` | [`vcat`](@ref) | shorthand for `cat(A...; dims=1) | +| `[A B C ...]` | [`hcat`](@ref) | shorthand for `cat(A...; dims=2) | +| `[A B; C D; ...]` | [`hvcat`](@ref) | simultaneous vertical and horizontal concatenation | + +### Typed array literals 可以用 `T[A, B, C, ...]` 的方式声明一个元素为某种特定类型的数组。该方法定义一个元素类型为 `T` 的一维数组并且初始化元素为 `A`, `B`, `C`, ....。比如,`Any[x, y, z]` 会构建一个异构数组,该数组可以包含任意类型的元素。 @@ -137,7 +200,7 @@ julia> Int8[[1 2] [3 4]] 1 2 3 4 ``` -## 数组推导 +## [Comprehensions](@id man-comprehensions) (数组)推导提供了构造数组的通用且强大的方法。其语法类似于数学中的集合构造的写法: @@ -171,7 +234,9 @@ julia> [ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ] 0.656511 ``` -生成的数组类型取决于参与计算元素的类型。为了明确地控制类型,可以在(数组)推导之前添加类型。例如,我们可以要求结果为单精度类型: +The resulting array type depends on the types of the computed elements just like [array literals](@ref man-array-literals) do. In order to control the +type explicitly, a type can be prepended to the comprehension. For example, we could have requested +the result in single precision by writing: ```julia Float32[ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ] @@ -202,7 +267,12 @@ julia> map(tuple, (1/(i+j) for i=1:2, j=1:2), [1 3; 2 4]) (0.333333, 2) (0.25, 4) ``` -生成器是通过内部函数实现。 与语言中其他地方使用的内部函数一样,封闭作用域中的变量可以在内部函数中被「捕获」。例如,`sum(p[i] - q[i] for i=1:n)` 从封闭作用域中捕获三个变量 `p`、`q` 和 `n`。捕获变量可能会出现性能问题;请参阅 [性能提示](@ref man-performance-tips)。 +Generators are implemented via inner functions. Just like +inner functions used elsewhere in the language, variables from the enclosing scope can be +"captured" in the inner function. For example, `sum(p[i] - q[i] for i=1:n)` +captures the three variables `p`, `q` and `n` from the enclosing scope. +Captured variables can present performance challenges; see +[performance tips](@ref man-performance-captured). 通过编写多个 `for` 关键字,生成器和推导中的范围可以取决于之前的范围: @@ -243,7 +313,7 @@ X = A[I_1, I_2, ..., I_n] 如果所有索引 `I_k` 都是向量,则 `X` 的形状将是 `(length(I_1), length(I_2), ..., length(I_n))`,其中,`X` 中位于 `i_1, i_2, ..., i_n` 处的元素为 `A[I_1[i_1], I_2[i_2], ..., I_n[i_n]]`。 -例子: +例如: ```jldoctest julia> A = reshape(collect(1:16), (2, 2, 2, 2)) @@ -337,7 +407,7 @@ julia> x[1, [2 3; 4 1]] 13 1 ``` -## 赋值 +## [Indexed Assignment](@id man-indexed-assignment) 在 n 维数组 `A` 中赋值的一般语法是: @@ -783,7 +853,13 @@ Julia 中的基本数组类型是抽象类型 [`AbstractArray{T,N}`](@ref)。它 `AbstractArray` 类型包含任何模糊类似的东西,它的实现可能与传统数组完全不同。例如,可以根据请求而不是存储来计算元素。但是,任何具体的 `AbstractArray{T,N}` 类型通常应该至少实现 [`size(A)`](@ref)(返回 `Int` 元组),[`getindex(A,i)`](@ref) 和 [`getindex(A,i1,...,iN)`](@ref getindex);可变数组也应该实现 [`setindex!`](@ref)。建议这些操作具有几乎为常数的时间复杂性,或严格说来 Õ(1) 复杂性,否则某些数组函数可能出乎意料的慢。具体类型通常还应提供 [`similar(A,T=eltype(A),dims=size(A))`](@ref) 方法,用于为 [`copy`](@ref) 分配类似的数组和其他位于当前数组空间外的操作。无论在内部如何表示 `AbstractArray{T,N}`,`T` 是由 *整数* 索引返回的对象类型(`A[1, ..., 1]`,当 `A` 不为空),`N` 应该是 [`size`](@ref) 返回的元组的长度。有关定义自定义 `AbstractArray` 实现的更多详细信息,请参阅[接口章节中的数组接口导则](@ref man-interface-array)。 -`DenseArray` 是 `AbstractArray` 的抽象子类型,旨在包含元素按列连续存储的所有数组(请参阅[性能建议](@ref man-performance-tips)中的附加说明)。[`Array`](@ref) 类型是 `DenseArray` 的特定实例;[`Vector`](@ref) 和 [`Matrix`](@ref) 是在一维和二维情况下的别名。除了所有 `AbstractArray` 所需的操作之外,很少有专门为 `Array` 实现的操作;大多数数组库都以通用方式实现,以保证所有自定义数组都具有相似功能。 +`DenseArray` is an abstract subtype of `AbstractArray` intended to include all arrays where +elements are stored contiguously in column-major order (see [additional notes in +Performance Tips](@ref man-performance-column-major)). The [`Array`](@ref) type is a specific instance +of `DenseArray`; [`Vector`](@ref) and [`Matrix`](@ref) are aliases for the 1-d and 2-d cases. +Very few operations are implemented specifically for `Array` beyond those that are required +for all `AbstractArray`s; much of the array library is implemented in a generic +manner that allows all custom arrays to behave similarly. `SubArray` 是 `AbstractArray` 的特例,它通过与原始数组共享内存而不是复制它来执行索引。 使用[`view`](@ref) 函数创建 `SubArray`,它的调用方式与[`getindex`](@ref) 相同(作用于数组和一系列索引参数)。 [`view`](@ref) 的结果看起来与 [`getindex`](@ref) 的结果相同,只是数据保持不变。 [`view`](@ref) 将输入索引向量存储在 `SubArray` 对象中,该对象稍后可用于间接索引原始数组。 通过将 [`@views`](@ref) 宏放在表达式或代码块之前,该表达式中的任何 `array [...]` 切片将被转换为创建一个 `SubArray` 视图。 diff --git a/zh_CN/doc/src/manual/calling-c-and-fortran-code.md b/zh_CN/doc/src/manual/calling-c-and-fortran-code.md index 58234412..16dbfcec 100644 --- a/zh_CN/doc/src/manual/calling-c-and-fortran-code.md +++ b/zh_CN/doc/src/manual/calling-c-and-fortran-code.md @@ -321,7 +321,7 @@ same: | C 类型 | Fortran 类型 | 标准 Julia 别名 | Julia 基本类型 | |:------------------------------------------------------- |:------------------------ |:-------------------- |:-------------------------------------------------------------------------------------------------------------- | | `unsigned char` | `CHARACTER` | `Cuchar` | `UInt8` | -| `bool` (only in C++) | | `Cuchar` | `UInt8` | +| `bool` (_Bool in C99+) | | `Cuchar` | `UInt8` | | `short` | `INTEGER*2`, `LOGICAL*2` | `Cshort` | `Int16` | | `unsigned short` |   | `Cushort` | `UInt16` | | `int`, `BOOL` (C, typical) | `INTEGER*4`, `LOGICAL*4` | `Cint` | `Int32` | @@ -908,6 +908,10 @@ function qsort(a::Vector{T}, cmp) where T end ``` +!!! note + Closure [`@cfunction`](@ref) rely on LLVM trampolines, which are not available on all + platforms (for example ARM and PowerPC). + ## 关闭库 diff --git a/zh_CN/doc/src/manual/constructors.md b/zh_CN/doc/src/manual/constructors.md index 314f3cb5..48b28c16 100644 --- a/zh_CN/doc/src/manual/constructors.md +++ b/zh_CN/doc/src/manual/constructors.md @@ -18,14 +18,30 @@ julia> foo.baz 2 ``` -对很多类型来说,通过给所有字段赋值来创建新对象的这种方式就足以用于产生新实例了。然而,在某些情形下,创建复合对象需要更多的功能。有时必须通过检查或转化参数来确保固有属性不变。[递归数据结构](https://en.wikipedia.org/wiki/Recursion_%28computer_science%29#Recursive_data_structures_.28structural_recursion.29),特别是那些可能引用自身的数据结构,它们通常不能被干净地构造,而是需要首先被不完整地构造,然后再通过编程的方式完成补全。为了方便,有时需要用较少的参数或者不同类型的参数来创建对象,Julia 的对象构造系统解决了所有这些问题。 +For many types, forming new objects by binding their field values together is all that is ever +needed to create instances. However, in some cases more functionality is required when +creating composite objects. Sometimes invariants must be enforced, either by checking arguments +or by transforming them. [Recursive data structures](https://en.wikipedia.org/wiki/Recursion_%28computer_science%29#Recursive_data_structures_.28structural_recursion.29), +especially those that may be self-referential, often cannot be constructed cleanly without first +being created in an incomplete state and then altered programmatically to be made whole, as a +separate step from object creation. Sometimes, it's just convenient to be able to construct objects +with fewer or different types of parameters than they have fields. Julia's system for object construction +addresses all of these cases and more. [^1]: - 命名法:虽然术语「构造函数」通常是指用于构造类型对象的函数全体,但通常会略微滥用术语将特定的构造方法称为「构造函数」。在这种情况下,通常可以从上下文中清楚地辨别出术语表示的是「构造方法」而不是「构造函数」,尤其是在讨论某个特别的「构造方法」的时候。 + Nomenclature: while the term "constructor" generally refers to the entire function which constructs + objects of a type, it is common to abuse terminology slightly and refer to specific constructor + methods as "constructors". In such situations, it is generally clear from the context that the term + is used to mean "constructor method" rather than "constructor function", especially as it is often + used in the sense of singling out a particular method of the constructor from all of the others. -## 外部构造方法 +## [Outer Constructor Methods](@id man-outer-constructor-methods) -构造函数与 Julia 中的其他任何函数一样,其整体行为由其各个方法的组合行为定义。因此,只要定义新方法就可以向构造函数添加功能。例如,假设你想为 `Foo` 对象添加一个构造方法,该方法只接受一个参数并其作为 `bar` 和 `baz` 的值。这很简单: +A constructor is just like any other function in Julia in that its overall behavior is defined +by the combined behavior of its methods. Accordingly, you can add functionality to a constructor +by simply defining new methods. For example, let's say you want to add a constructor method for +`Foo` objects that takes only one argument and uses the given value for both the `bar` and `baz` +fields. This is simple: ```jldoctest footype julia> Foo(x) = Foo(x,x) @@ -45,16 +61,27 @@ julia> Foo() Foo(0, 0) ``` -这里零参数构造方法会调用单参数构造方法,单参数构造方法又调用了自动提供默认值的双参数构造方法。上面附加的这类构造方法,它们的声明方式与普通的方法一样,像这样的构造方法被称为**外部**构造方法,下文很快就会揭示这样称呼的原因。外部构造方法只能通过调用其他构造方法来创建新实例,比如自动提供默认值的构造方法。 +Here the zero-argument constructor method calls the single-argument constructor method, which +in turn calls the automatically provided two-argument constructor method. For reasons that will +become clear very shortly, additional constructor methods declared as normal methods like this +are called *outer* constructor methods. Outer constructor methods can only ever create a new instance +by calling another constructor method, such as the automatically provided default ones. -## 内部构造方法 +## [Inner Constructor Methods](@id man-inner-constructor-methods) -尽管外部构造方法可以成功地为构造对象提供了额外的便利,但它无法解决另外两个在本章导言里提到的问题:确保固有属性不变和允许创建自引用对象。因此,我们需要**内部**构造方法。内部构造方法和外部构造方法很相像,但有两点不同: +While outer constructor methods succeed in addressing the problem of providing additional convenience +methods for constructing objects, they fail to address the other two use cases mentioned in the +introduction of this chapter: enforcing invariants, and allowing construction of self-referential +objects. For these problems, one needs *inner* constructor methods. An inner constructor method +is like an outer constructor method, except for two differences: -1. 内部构造方法在类型声明代码块的内部,而不是和普通方法一样在外部。 -2. 内部构造方法能够访问一个特殊的局部函数 [`new`](@ref),此函数能够创建该类型的对象。 +1. It is declared inside the block of a type declaration, rather than outside of it like normal methods. +2. It has access to a special locally existent function called [`new`](@ref) that creates objects of the + block's type. -例如,假设你要声明一个保存一对实数的类型,但要约束第一个数不大于第二个数。你可以像这样声明它: +For example, suppose one wants to declare a type that holds a pair of real numbers, subject to +the constraint that the first number is not greater than the second one. One could declare it +like this: ```jldoctest pairtype julia> struct OrderedPair diff --git a/zh_CN/doc/src/manual/control-flow.md b/zh_CN/doc/src/manual/control-flow.md index 4030e6dd..e97ed8f7 100644 --- a/zh_CN/doc/src/manual/control-flow.md +++ b/zh_CN/doc/src/manual/control-flow.md @@ -2,7 +2,7 @@ Julia 提供了大量的流程控制构件: - * [复合表达式](@ref man-compound-expressions):`begin` 和 `(;)`。 + * [Compound Expressions](@ref man-compound-expressions): `begin` and `;`. * [条件表达式](@ref man-conditional-evaluation):`if`-`elseif`-`else` 和 `?:` (三元运算符)。 * [短路求值](@ref):`&&`、`||` 和链式比较。 * [重复执行:循环](@ref man-loops):`while` 和 `for`。 @@ -13,7 +13,10 @@ Julia 提供了大量的流程控制构件: ## [复合表达式](@id man-compound-expressions) -有时一个表达式能够有序地计算若干子表达式,并返回最后一个子表达式的值作为它的值是很方便的。Julia 有两个组件来完成这个: `begin` 代码块 和 `(;)` 链。这两个复合表达式组件的值都是最后一个子表达式的值。下面是一个 `begin` 代码块的例子: +Sometimes it is convenient to have a single expression which evaluates several subexpressions +in order, returning the value of the last subexpression as its value. There are two Julia constructs +that accomplish this: `begin` blocks and `;` chains. The value of both compound expression constructs +is that of the last subexpression. Here's an example of a `begin` block: ```jldoctest julia> z = begin @@ -24,14 +27,17 @@ julia> z = begin 3 ``` -因为这些是非常简短的表达式,它们可以简单地被放到一行里,这也是 `(;)` 链的由来: +Since these are fairly small, simple expressions, they could easily be placed onto a single line, +which is where the `;` chain syntax comes in handy: ```jldoctest julia> z = (x = 1; y = 2; x + y) 3 ``` -这个语法在定义简洁的单行函数的时候特别有用,参见 [函数](@id man-functions)。尽管很典型,但是并不要求 `begin` 代码块是多行的,或者 `(;)` 链是单行的: +This syntax is particularly useful with the terse single-line function definition form introduced +in [Functions](@ref). Although it is typical, there is no requirement that `begin` blocks be multiline +or that `;` chains be single-line: ```jldoctest julia> begin x = 1; y = 2; x + y end diff --git a/zh_CN/doc/src/manual/conversion-and-promotion.md b/zh_CN/doc/src/manual/conversion-and-promotion.md index e5d3a89c..7ebd9cee 100644 --- a/zh_CN/doc/src/manual/conversion-and-promotion.md +++ b/zh_CN/doc/src/manual/conversion-and-promotion.md @@ -65,7 +65,8 @@ julia> convert(Array{Float64}, a) 4.0 5.0 6.0 ``` -类型转换并不总是可行的,有时 `convert` 函数并不知道该如何执行所请求的类型转换就会抛出 no method error 错误。例如下例: +Conversion isn't always possible, in which case a [`MethodError`](@ref) is thrown indicating that `convert` +doesn't know how to perform the requested conversion: ```jldoctest julia> convert(AbstractFloat, "foo") diff --git a/zh_CN/doc/src/manual/documentation.md b/zh_CN/doc/src/manual/documentation.md index 0089a6d3..201d2b54 100644 --- a/zh_CN/doc/src/manual/documentation.md +++ b/zh_CN/doc/src/manual/documentation.md @@ -17,7 +17,9 @@ foo(xs::Array) = ... 其它字符串宏并传递给 `@doc` 宏来使用其他格式。 !!! note - Markdown 支持由 `Markdown` 标准库实现,有关支持语法的完整列表,请参阅其[文档](@ref Markdown)。 + Markdown support is implemented in the `Markdown` standard library + and for a full list of supported syntax see the + [documentation](@ref markdown_stdlib). 这里是一个更加复杂的例子,但仍然使用 Markdown: diff --git a/zh_CN/doc/src/manual/faq.md b/zh_CN/doc/src/manual/faq.md index aae2088b..0c7f595d 100644 --- a/zh_CN/doc/src/manual/faq.md +++ b/zh_CN/doc/src/manual/faq.md @@ -56,7 +56,7 @@ obj3 = MyModule.someotherfunction(obj2, c) 当一个文件通过使用 `julia file.jl` 来当做主脚本运行时,有人也希望激活另外的功能例如命令行参数操作。确定文件是以这个方式运行的一个方法是检查 `abspath(PROGRAM_FILE) == @__FILE__` 是不是 `true`。 -### 怎样在脚本中捕获 CTRL-C ? +### [How do I catch CTRL-C in a script?](@id catch-ctrl-c) 通过 `julia file.jl` 方式运行的 Julia 脚本,在你尝试按 CTRL-C (SIGINT) 中止它时,并不会抛出 [`InterruptException`](@ref)。如果希望在脚本终止之后运行一些代码,请使用 [`atexit`](@ref),注意:脚本的中止不一定是由 CTRL-C 导致的。 另外你也可以通过 `julia -e 'include(popfirst!(ARGS))' file.jl` 命令运行脚本,然后可以通过 [`try`](@ref) 捕获 `InterruptException`。 @@ -70,17 +70,29 @@ obj3 = MyModule.someotherfunction(obj2, c) ```julia #!/bin/bash #= -exec julia --color=yes --startup-file=no -e 'include(popfirst!(ARGS))' \ - "${BASH_SOURCE[0]}" "$@" +exec julia --color=yes --startup-file=no "${BASH_SOURCE[0]}" "$@" =# -@show ARGS # 把你的 Julia 代码放在这里 +@show ARGS # put any Julia code here ``` 在以上例子中,位于 `#=` 和 `=#` 之间的代码可以当作一个 `bash` 脚本。 因为这些代码放在 Julia 的多行注释中,所以 Julia 会忽略它们。 在 `=#` 之后的 Julia 代码会被 `bash` 忽略,J因为当文件解析到 `exec` 语句时会停止解析,开始执行命令。 +!!! note + In order to [catch CTRL-C](@ref catch-ctrl-c) in the script you can use + ```julia + #!/bin/bash + #= + exec julia --color=yes --startup-file=no -e 'include(popfirst!(ARGS))' \ + "${BASH_SOURCE[0]}" "$@" + =# + + @show ARGS # put any Julia code here + ``` + instead. Note that with this strategy [`PROGRAM_FILE`](@ref) will not be set. + ## 函数 ### 向函数传递了参数 `x`,在函数中做了修改,但是在函数外变量 `x` 的值还是没有变。为什么? @@ -303,6 +315,45 @@ julia> sqrt(-2.0+0im) 0.0 + 1.4142135623730951im ``` +### How can I constrain or compute type parameters? + +The parameters of a [parametric type](@ref Parametric-Types) can hold either +types or bits values, and the type itself chooses how it makes use of these parameters. +For example, `Array{Float64, 2}` is parameterized by the type `Float64` to express its +element type and the integer value `2` to express its number of dimensions. When +defining your own parametric type, you can use subtype constraints to declare that a +certain parameter must be a subtype ([`<:`](@ref)) of some abstract type or a previous +type parameter. There is not, however, a dedicated syntax to declare that a parameter +must be a _value_ of a given type — that is, you cannot directly declare that a +dimensionality-like parameter [`isa`](@ref) `Int` within the `struct` definition, for +example. Similarly, you cannot do computations (including simple things like addition +or subtraction) on type parameters. Instead, these sorts of constraints and +relationships may be expressed through additional type parameters that are computed +and enforced within the type's [constructors](@ref man-constructors). + +As an example, consider +```julia +struct ConstrainedType{T,N,N+1} # NOTE: INVALID SYNTAX + A::Array{T,N} + B::Array{T,N+1} +end +``` +where the user would like to enforce that the third type parameter is always the second plus one. This can be implemented with an explicit type parameter that is checked by an [inner constructor method](@ref man-inner-constructor-methods) (where it can be combined with other checks): +```julia +struct ConstrainedType{T,N,M} + A::Array{T,N} + B::Array{T,M} + function ConstrainedType(A::Array{T,N}, B::Array{T,M}) where {T,N,M} + N + 1 == M || throw(ArgumentError("second argument should have one more axis" )) + new{T,N,M}(A, B) + end +end +``` +This check is usually *costless*, as the compiler can elide the check for valid concrete types. If the second argument is also computed, it may be advantageous to provide an [outer constructor method](@ref man-outer-constructor-methods) that performs this calculation: +```julia +ConstrainedType(A) = ConstrainedType(A, compute_B(A)) +``` + ### [Why does Julia use native machine integer arithmetic?](@id faq-integer-arithmetic) Julia使用机器算法进行整数计算。这意味着`Int`的范围是有界的,值在范围的两端循环,也就是说整数的加法,减法和乘法会出现上溢或者下溢,导致出现某些从开始就令人不安的结果: @@ -468,6 +519,14 @@ Source line: 5 让整数算法静默溢出的最合理的备用方案是所有地方都使用检查算法,当加法、减法和乘法溢出,产生不正确的值时引发错误。在[blog post](http://danluu.com/integer-overflow/)中,Dan Luu分析了这个方案,发现这个方案理论上的性能微不足道,但是最终仍然会消耗大量的性能因为编译器(LLVM和GCC)无法在加法溢出检测处优雅地进行优化。如果未来有所进步我们会考虑在Julia中默认设置为检查整数算法,但是现在,我们需要和溢出可能共同相处。 +In the meantime, overflow-safe integer operations can be achieved through the use of external libraries +such as [SaferIntegers.jl](https://github.com/JeffreySarnoff/SaferIntegers.jl). Note that, as stated +previously, the use of these libraries significantly increases the execution time of code using the +checked integer types. However, for limited usage, this is far less of an issue than if it were used +for all integer operations. You can follow the status of the discussion +[here](https://github.com/JuliaLang/julia/issues/855). + + ### 在远程执行中`UndefVarError`的可能原因有哪些? 如同这个错误表述的,远程结点上的`UndefVarError`的直接原因是变量名的绑定并不存在。让我们探索一下一些可能的原因。 diff --git a/zh_CN/doc/src/manual/functions.md b/zh_CN/doc/src/manual/functions.md index 473851c7..65fb6a4b 100644 --- a/zh_CN/doc/src/manual/functions.md +++ b/zh_CN/doc/src/manual/functions.md @@ -9,6 +9,9 @@ julia> function f(x,y) f (generic function with 1 method) ``` +This function accepts two arguments `x` and `y` and returns the value +of the last expression evaluated, which is `x + y`. + 在 Julia 中定义函数还有第二种更简洁的语法。上述的传统函数声明语法等效于以下紧凑性的“赋值形式”: ```jldoctest fofxy @@ -50,7 +53,12 @@ Julia 函数参数遵循有时称为 “pass-by-sharing” 的约定,这意味 ## `return` 关键字 -函数返回的值是最后计算的表达式的值,默认情况下,它是函数定义主体中的最后一个表达式。在示例函数中 `f`,从上一节开始,这是表达式的 `x + y` 值。与在 C 语言和大多数其他命令式或函数式语言中一样,`return` 关键字会导致函数立即返回,从而提供返回值的表达式: +The value returned by a function is the value of the last expression evaluated, which, by default, +is the last expression in the body of the function definition. In the example function, `f`, from +the previous section this is the value of the expression `x + y`. +As an alternative, as in many other languages, +the `return` keyword causes a function to return immediately, providing +an expression whose value is returned: ```julia function g(x,y) @@ -104,7 +112,10 @@ julia> hypot(3, 4) 这个函数有三个可能的返回处,返回三个不同表达式的值,具体取决于 `x` 和 `y` 的值。 最后一行的 `return` 可以省略,因为它是最后一个表达式。 -也可以使用 `::` 运算符在函数声明中指定返回类型。 这可以将返回值转换为指定的类型。 +### 返回类型 + +A return type can be specified in the function declaration using the `::` operator. This converts +the return value to the specified type. ```jldoctest julia> function g(x, y)::Int8 @@ -117,6 +128,30 @@ Int8 这个函数将忽略 `x` 和 `y` 的类型,返回 `Int8` 类型的值。有关返回类型的更多信息,请参见[类型声明](@ref)。 +### Returning nothing + +For functions that do not need to return a value (functions used only for some side effects), +the Julia convention is to return the value [`nothing`](@ref): + +```julia +function printx(x) + println("x = $x") + return nothing +end +``` + +This is a *convention* in the sense that `nothing` is not a Julia keyword +but a only singleton object of type `Nothing`. +Also, you may notice that the `printx` function example above is contrived, +because `println` already returns `nothing`, so that the `return` line is redundant. + +There are two possible shortened forms for the `return nothing` expression. +On the one hand, the `return` keyword implicitly returns `nothing`, so it can be used alone. +On the other hand, since functions implicitly return their last expression evaluated, +`nothing` can be used alone when it's the last expression. +The preference for the expression `return nothing` as opposed to `return` or `nothing` +alone is a matter of coding style. + ## 操作符也是函数 在 Julia中,大多数操作符只不过是支持特殊语法的函数( `&&` 和`||` 等具有特殊评估语义的操作符除外,他们不能是函数,因为[短路求值](@ref)要求在计算整个表达式的值之前不计算每个操作数)。因此,您也可以使用带括号的参数列表来使用它们,就和任何其他函数一样: @@ -563,7 +598,10 @@ end 使用 `do` 代码块语法时,查阅文档或实现有助于了解用户函数的参数是如何初始化的。 -与任何其它内部函数一样,`do` 代码块可以从包含它的作用域里「捕获」变量。例如,在上例的 `open...do` 中,`data` 变量是从外部作用域中捕获的。捕获变量也许会带来在 [performance tips](@ref man-performance-tips) 中讨论的性能挑战。 +A `do` block, like any other inner function, can "capture" variables from its +enclosing scope. For example, the variable `data` in the above example of +`open...do` is captured from the outer scope. Captured variables +can create performance challenges as discussed in [performance tips](@ref man-performance-captured). ## Function composition and piping @@ -665,7 +703,15 @@ julia> f.(A, B) 此外,*嵌套的* `f.(args...)` 调用会被*融合*到一个 `broadcast` 循环中。例如,`sin.(cos.(X))` 等价于 `broadcast(x -> sin(cos(x)), X)`,类似于 `[sin(cos(x)) for x in X]`:在 `X` 上只有一个循环,并且只为结果分配了一个数组。[ 相反,在典型的「向量化」语言中,`sin(cos(X))` 首先会为 `tmp=cos(X)` 分配第一个临时数组,然后在单独的循环中计算 `sin(tmp)`,再分配第二个数组。] 这种循环融合不是可能发生也可能不发生的编译器优化,只要遇到了嵌套的 `f.(args...)` 调用,它就是一个*语法保证*。技术上,一旦遇到「非点」函数调用,融合就会停止;例如,在 `sin.(sort(cos.(X)))` 中,由于插入的 `sort` 函数,`sin` 和 `cos` 无法被合并。 -最后,最大效率通常在向量化操作的输出数组被*预分配*时实现,以便重复调用不会一次又一次地为结果分配新数组(请参阅 [输出预分配](@ref))。一个方便的语法是 `X .= ...`,它等价于 `broadcast!(identity, X, ...)`,除了上面提到的,`broadcast!` 循环可与任何嵌套的「点」调用融合。例如,`X .= sin.(Y)` 等价于 `broadcast!(sin, X, Y)`,用 `sin.(Y)` in-place 覆盖 `X`。如果左边是数组索引表达式,例如 `X[2:end] .= sin.(Y)`,那就将 `broadcast!` 转换在一个 `view` 上,例如 `broadcast!(sin, view(X, 2:lastindex(X)), Y)`,这样左侧就被 in-place 更新了。 +Finally, the maximum efficiency is typically achieved when the output array of a vectorized operation +is *pre-allocated*, so that repeated calls do not allocate new arrays over and over again for +the results (see [Pre-allocating outputs](@ref)). A convenient syntax for this is `X .= ...`, which +is equivalent to `broadcast!(identity, X, ...)` except that, as above, the `broadcast!` loop is +fused with any nested "dot" calls. For example, `X .= sin.(Y)` is equivalent to `broadcast!(sin, X, Y)`, +overwriting `X` with `sin.(Y)` in-place. If the left-hand side is an array-indexing expression, +e.g. `X[begin+1:end] .= sin.(Y)`, then it translates to `broadcast!` on a `view`, e.g. +`broadcast!(sin, view(X, firstindex(X)+1:lastindex(X)), Y)`, +so that the left-hand side is updated in-place. 由于在表达式中为许多操作和函数调用添加点可能很乏味并导致难以阅读的代码,宏 [`@.`](@ref @__dot__) 用于将表达式中的*每个*函数调用、操作和赋值转换为「点」版本。 diff --git a/zh_CN/doc/src/manual/integers-and-floating-point-numbers.md b/zh_CN/doc/src/manual/integers-and-floating-point-numbers.md index ebf9717b..4823920a 100644 --- a/zh_CN/doc/src/manual/integers-and-floating-point-numbers.md +++ b/zh_CN/doc/src/manual/integers-and-floating-point-numbers.md @@ -185,7 +185,10 @@ julia> for T in [Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt12 UInt128: [0,340282366920938463463374607431768211455] ``` -[`typemin`](@ref) 和 [`typemax`](@ref) 返回的值的类型总与所给参数的类型相同。(上面的表达式用了一些目前还没有介绍的功能,包括 [for 循环](@ref man-loops)、[字符串](@ref man-strings)和[插值](@ref),但对于已有一些编程经验的用户应该是很容易理解的。) +The values returned by [`typemin`](@ref) and [`typemax`](@ref) are always of the given argument +type. (The above expression uses several features that have yet to be introduced, including [for loops](@ref man-loops), +[Strings](@ref man-strings), and [Interpolation](@ref string-interpolation), but should be easy enough to understand for users +with some existing programming experience.) ### 溢出行为 @@ -459,15 +462,23 @@ Julia 所使用的默认模式总是 [`RoundNearest`](@ref),指舍入到最接 为了允许使用任意精度的整数与浮点数,Julia 分别包装了 [GNU Multiple Precision Arithmetic Library (GMP)](https://gmplib.org) 以及 [GNU MPFR Library](https://www.mpfr.org)。Julia 中的 [`BigInt`](@ref) 与 [`BigFloat`](@ref) 两种类型分别提供了任意精度的整数和浮点数。 -存在从原始数字类型创建它们的构造器,也可以使用 [`parse`](@ref) 从 `AbstractString` 来构造它们。一旦被创建,它们就可以像所有其它数值类型一样参与算术(也是多亏了 Julia 的[类型提升和转换机制](@ref conversion-and-promotion))。 +Constructors exist to create these types from primitive numerical types, and the [string literal](@ref non-standard-string-literals) [`@big_str`](@ref) or [`parse`](@ref) +can be used to construct them from `AbstractString`s. Once created, they participate in arithmetic +with all other numeric types thanks to Julia's [type promotion and conversion mechanism](@ref conversion-and-promotion): ```jldoctest julia> BigInt(typemax(Int64)) + 1 9223372036854775808 +julia> big"123456789012345678901234567890" + 1 +123456789012345678901234567891 + julia> parse(BigInt, "123456789012345678901234567890") + 1 123456789012345678901234567891 +julia> big"1.23456789012345678901" +1.234567890123456789010000000000000000000000000000000000000000000000000000000004 + julia> parse(BigFloat, "1.23456789012345678901") 1.234567890123456789010000000000000000000000000000000000000000000000000000000004 diff --git a/zh_CN/doc/src/manual/interfaces.md b/zh_CN/doc/src/manual/interfaces.md index f4862d25..f930e8cd 100644 --- a/zh_CN/doc/src/manual/interfaces.md +++ b/zh_CN/doc/src/manual/interfaces.md @@ -135,16 +135,18 @@ julia> collect(Iterators.reverse(Squares(4))) 1 ``` -## 索引 +## Indexing -| 需要实现的方法 | 简介 | +| Methods to implement | Brief description | |:-------------------- |:-------------------------------- | -| `getindex(X, i)` | `X[i]`,索引元素访问 | -| `setindex!(X, v, i)` | `X[i] = v`,索引元素赋值 | -| `firstindex(X)` | 第一个索引 | -| `lastindex(X)` | 最后一个索引,用于 `X[end]` | +| `getindex(X, i)` | `X[i]`, indexed element access | +| `setindex!(X, v, i)` | `X[i] = v`, indexed assignment | +| `firstindex(X)` | The first index, used in `X[begin]` | +| `lastindex(X)` | The last index, used in `X[end]` | -对于 `Squares` 类型而言,可以通过对第 `i` 个元素求平方计算出其中的第 `i` 个元素,可以用 `S[i]` 的索引表达式形式暴露该接口。为了支持该行为,`Squares` 只需要简单地定义 [`getindex`](@ref): +For the `Squares` iterable above, we can easily compute the `i`th element of the sequence by squaring +it. We can expose this as an indexing expression `S[i]`. To opt into this behavior, `Squares` +simply needs to define [`getindex`](@ref): ```jldoctest squaretype julia> function Base.getindex(S::Squares, i::Int) @@ -156,7 +158,8 @@ julia> Squares(100)[23] 529 ``` -另外,为了支持语法 `S[end]`,我们必须定义 [`lastindex`](@ref) 来指定最后一个有效索引。建议也定义 [`firstindex`](@ref) 来指定第一个有效索引: +Additionally, to support the syntax `S[begin]` and `S[end]`, we must define [`firstindex`](@ref) and +[`lastindex`](@ref) to specify the first and last valid indices, respectively: ```jldoctest squaretype julia> Base.firstindex(S::Squares) = 1 @@ -195,7 +198,7 @@ julia> Squares(10)[[3,4.,5]] | **可选方法** | **默认定义** | **简短描述** | | `IndexStyle(::Type)` | `IndexCartesian()` | 返回 `IndexLinear()` 或 `IndexCartesian()`。请参阅下文描述。 | | `getindex(A, I...)` | 基于标量 `getindex` 定义 | [多维非标量索引](@ref man-array-indexing) | -| `setindex!(A, I...)` | 基于标量 `setindex!` 定义 | [多维非标量索引元素赋值](@ref man-array-indexing) | +| `setindex!(A, X, I...)` | 基于标量 `setindex!` 定义 | [多维非标量索引元素赋值](@ref man-array-indexing) | | `iterate` | 基于标量 `getindex` 定义 | Iteration | | `length(A)` | `prod(size(A))` | 元素数 | | `similar(A)` | `similar(A, eltype(A), size(A))` | 返回具有相同形状和元素类型的可变数组 | @@ -462,10 +465,11 @@ end find_aac(bc::Base.Broadcast.Broadcasted) = find_aac(bc.args) find_aac(args::Tuple) = find_aac(find_aac(args[1]), Base.tail(args)) find_aac(x) = x +find_aac(::Tuple{}) = nothing find_aac(a::ArrayAndChar, rest) = a find_aac(::Any, rest) = find_aac(rest) # output -find_aac (generic function with 5 methods) +find_aac (generic function with 6 methods) ``` 在这些定义中,可以得到以下行为: diff --git a/zh_CN/doc/src/manual/mathematical-operations.md b/zh_CN/doc/src/manual/mathematical-operations.md index fbfbc57e..f717ac78 100644 --- a/zh_CN/doc/src/manual/mathematical-operations.md +++ b/zh_CN/doc/src/manual/mathematical-operations.md @@ -193,7 +193,7 @@ false * 有限数的大小顺序,和我们所熟知的相同。 * `+0` 等于但不大于 `-0`. * `Inf` 等于自身,并且大于除了 `NaN` 外的所有数。 - * `-Inf` 等于自身,并且小于除了 `NaN` 外的所有数。 + * `-Inf` is equal to itself and less than everything else except `NaN`. * `NaN` 不等于、不小于且不大于任何数值,包括它自己。 `NaN` 不等于它自己这一点可能会令人感到惊奇,所以需要注意: @@ -328,9 +328,9 @@ Julia 提供了强大的数学函数和运算符集合。这些数学运算定 ```jldoctest julia> Base.operator_precedence(:+), Base.operator_precedence(:*), Base.operator_precedence(:.) -(11, 13, 17) +(11, 12, 17) -julia> Base.operator_precedence(:sin), Base.operator_precedence(:+=), Base.operator_precedence(:(=)) #(请注意 `:(=)` 中的括号是必要的) +julia> Base.operator_precedence(:sin), Base.operator_precedence(:+=), Base.operator_precedence(:(=)) # (Note the necessary parens on `:(=)`) (0, 1, 1) ``` diff --git a/zh_CN/doc/src/manual/metaprogramming.md b/zh_CN/doc/src/manual/metaprogramming.md index da93f5ec..7ab827f0 100644 --- a/zh_CN/doc/src/manual/metaprogramming.md +++ b/zh_CN/doc/src/manual/metaprogramming.md @@ -178,7 +178,7 @@ julia> typeof(ex) Expr ``` -### 插值 +### [Interpolation](@id man-expression-interpolation) Direct construction of [`Expr`](@ref) objects with value arguments is powerful, but `Expr` constructors can be tedious compared to "normal" Julia syntax. As an alternative, Julia allows *interpolation* of @@ -230,14 +230,17 @@ julia> x = :(1 + 2); julia> e = quote quote $x end end quote #= none:1 =# - $(Expr(:quote, quote - #= none:1 =# - $(Expr(:$, :x)) -end)) + quote + #= none:1 =# + $x + end end ``` -请注意,结果包含 `Expr(:$, :x)`,这意味着 `x` 还未被求值。换种说法,`$` 表达式「属于」内层引用表达式,所以它的参数只在内层引用表达式被求值时进行求值: +Notice that the result contains `$x`, which means that `x` has not been +evaluated yet. +In other words, the `$` expression "belongs to" the inner quote expression, and +so its argument is only evaluated when the inner quote expression is: ```jldoctest interp1 julia> eval(e) @@ -253,14 +256,15 @@ end julia> e = quote quote $$x end end quote #= none:1 =# - $(Expr(:quote, quote - #= none:1 =# - $(Expr(:$, :(1 + 2))) -end)) + quote + #= none:1 =# + $(1 + 2) + end end ``` -请注意,现在的结果中出现的是 `:(1 + 2)` 而不是符号 `:x`。求解此表达式产生一个被插值的 `3`: +Notice that `(1 + 2)` now appears in the result instead of the symbol `x`. +Evaluating this expression yields an interpolated `3`: ```jldoctest interp1 julia> eval(e) @@ -484,11 +488,14 @@ julia> @macroexpand @sayhello "human" :(println("Hello, ", "human")) ``` -### 注意:为何使用宏? +### Hold up: why macros? -我们在前一节中已经见过 `f(::Expr...) -> Expr` 形式的函数。事实上,[`macroexpand`](@ref) 也是这样的函数。所以,宏为何存在? +We have already seen a function `f(::Expr...) -> Expr` in a previous section. In fact, [`macroexpand`](@ref) +is also such a function. So, why do macros exist? -宏是必需的,因为其在代码解析时执行,于是,宏允许程序员在整个程序运行*前*生成并包含自定义的代码片段。为了说明此差异,请考虑以下示例: +Macros are necessary because they execute when code is parsed, therefore, macros allow the programmer +to generate and include fragments of customized code *before* the full program is run. To illustrate +the difference, consider the following example: ```julia-repl whymacros julia> macro twostep(arg) @@ -498,7 +505,7 @@ julia> macro twostep(arg) @twostep (macro with 1 method) julia> ex = macroexpand(Main, :(@twostep :(1, 2, 3)) ); -I execute at parse time. The argument is: $(Expr(:quote, :((1, 2, 3)))) +I execute at parse time. The argument is: :((1, 2, 3)) ``` 第一个 [`println`](@ref) 调用在调用 [`macroexpand`](@ref) 时执行。生成的表达式*只*包含第二个 `println`: @@ -1113,7 +1120,10 @@ baz (generic function with 1 method) ### 一个高级的例子 -Julia 的 base 库有个内部函数 `sub2ind`,用于根据一组 n 重线性索引计算 n 维数组的线性索引——换句话说,用于计算索引 `i`,其可用于使用 `A[i]` 来索引数组 `A`,而不是用 `A[x,y,z,...]`。一种可能的实现如下: +Julia's base library has an internal `sub2ind` function to calculate a linear index into an n-dimensional +array, based on a set of n multilinear indices - in other words, to calculate the index `i` that +can be used to index into an array `A` using `A[i]`, instead of `A[x,y,z,...]`. One possible implementation +is the following: ```jldoctest sub2ind julia> function sub2ind_loop(dims::NTuple{N}, I::Integer...) where N diff --git a/zh_CN/doc/src/manual/noteworthy-differences.md b/zh_CN/doc/src/manual/noteworthy-differences.md index 914b12c9..54456a02 100644 --- a/zh_CN/doc/src/manual/noteworthy-differences.md +++ b/zh_CN/doc/src/manual/noteworthy-differences.md @@ -78,7 +78,8 @@ * 类似于提取(或「解引用」)元胞数组的所有元素的操作,例如 MATLAB 中的 `vertcat(A{:})`,在 Julia 中是使用 splat 运算符编写的,例如 `vcat(A...)`。 - + * In Julia, the `adjoint` function performs conjugate transposition; in MATLAB, `adjoint` provides the "adjugate" or + classical adjoint, which is the transpose of the matrix of cofactors. ## 与 R 的显著差异 Julia 的目标之一是为数据分析和统计编程提供高效的语言。对于从 R 转到 Julia 的用户来说,这是一些显著差异: @@ -201,12 +202,12 @@ Julia 的目标之一是为数据分析和统计编程提供高效的语言。 * Julia 的 `for`、`if`、`while`等代码块由`end`关键字终止。缩进级别并不像在 Python 中那么重要。 - * Julia 没有用来续行的语法:如果在行的末尾,到目前为止的输入是一个完整的表达式,则认为已经结束;否则,认为输入继续。强制表达式继续的一种方式是将其包含在括号中。 + * Julia 没有用来续行的语法:如果在行的末尾,到目前为止的输入是一个完整的表达式,则认为其已经结束;否则,认为输入继续。强制表达式继续的一种方式是将其包含在括号中。 * 默认情况下,Julia 数组是列优先的(Fortran 顺序),而 NumPy 数组是行优先(C 顺序)。为了在循环数组时获得最佳性能,循环顺序应该在 Julia 中相对于 NumPy 反转(请参阅 [Performance Tips](@ref man-performance-tips) 中的对应章节)。 - + be reversed in Julia relative to NumPy (see [relevant section of Performance Tips](@ref man-performance-column-major)). * Julia 的更新运算符(例如 `+=`,`-=`,···)是 *not in-place*,而 Numpy 的是。这意味着 `A = [1, 1]; B = A; B += [3, 3]` 不会改变 `A` 中的值,而将名称 `B` 重新绑定到右侧表达式 `B = B + 3` 的结果,这是一个新的数组。对于 in-place 操作,使用 `B .+= 3`(另请参阅 [dot operators](@ref man-dot-operators))、显式的循环或者 `InplaceOps.jl`。 @@ -232,7 +233,7 @@ Julia 的目标之一是为数据分析和统计编程提供高效的语言。 * Julia 的数组是列优先的(Fortran 顺序),而 C/C++ 的数组默认是行优先的。要使数组上的循环性能最优,在 Julia 中循环的顺序应该与 C/C++ 相反(参见 [性能建议](@ref man-performance-tips))。 - + reversed in Julia relative to C/C++ (see [relevant section of Performance Tips](@ref man-performance-column-major)). * Julia 的值在赋值或向函数传递时不发生复制。如果某个函数修改了数组,这一修改对调用者是可见的。 * 在 Julia 中,空格是有意义的,这与 C/C++ 不同,所以向 Julia 程序中添加或删除空格时必须谨慎。 diff --git a/zh_CN/doc/src/manual/parallel-computing.md b/zh_CN/doc/src/manual/parallel-computing.md index cc24acad..43b53521 100644 --- a/zh_CN/doc/src/manual/parallel-computing.md +++ b/zh_CN/doc/src/manual/parallel-computing.md @@ -187,7 +187,8 @@ julia> @elapsed while n > 0 # 打印结果 # [Multi-Threading (Experimental)](@id man-multithreading) -除了 task 之外,Julia 还原生支持多线程。本部分内容是实验性的,未来相关接口可能会改变。 +In addition to tasks Julia natively supports multi-threading. +Note that this section is experimental and the interfaces may change in the future. ## 设置 @@ -201,11 +202,24 @@ julia> Threads.nthreads() Julia 启动时的线程数可以通过环境变量 `JULIA_NUM_THREADS` 设置,下面启动4个线程: +Bash on Linux/OSX: + ```bash export JULIA_NUM_THREADS=4 ``` -(上面的代码只能在 Linux 和 OSX 系统中运行,如果你在以上平台中使用的是 C shell,那么将 `export` 改成 `set`,如果你是在 Windows 上运行,那么将 `export` 改成 `set` 同时启动 Julia 时指定 `julia.exe` 的完整路径。) +C shell on Linux/OSX, CMD on Windows: + +```bash +set JULIA_NUM_THREADS=4 +``` + +Powershell on Windows: + +```powershell +$env:JULIA_NUM_THREADS=4 +``` + 现在确认下确实有4个线程: @@ -336,7 +350,14 @@ julia> acc[] ## 副作用和可变的函数参数 -在使用多线程时,要非常小心使用了不[纯](https://en.wikipedia.org/wiki/Pure_function)的函数,例如,用到了[以!结尾](https://docs.julialang.org/en/latest/manual/style-guide/#Append-!-to-names-of-functions-that-modify-their-arguments-1)的函数,通常这类函数会修改其参数,因而是不纯的。此外还有些函数没有以 `!` 结尾,其实也是有副作用的,比如 [`findfirst(regex, str)`](@ref) 就会改变 `regex` 参数,或者是 [`rand()`](@ref) 会修改 `Base.GLOBAL_RNG`: +When using multi-threading we have to be careful when using functions that are not +[pure](https://en.wikipedia.org/wiki/Pure_function) as we might get a wrong answer. +For instance functions that have their +[name ending with `!`](@ref bang-convention) +by convention modify their arguments and thus are not pure. However, there are +functions that have side effects and their name does not end with `!`. For +instance [`findfirst(regex, str)`](@ref) mutates its `regex` argument or +[`rand()`](@ref) changes `Base.GLOBAL_RNG` : ```julia-repl julia> using Base.Threads @@ -646,8 +667,10 @@ julia> addprocs(2) 在 master 主线程中,`Distributed` 模块必须显式地在调用 [`addprocs`](@ref) 之前载入,该模块会自动在其它进程中可见。 -需要注意的时,worker 进程并不会执行 `~/.julia/config/startup.jl` 启动脚本,也不会同步其它进程的全局状态(比如全局变量,新定义的方法,加载的模块等)。 - +Note that workers do not run a `~/.julia/config/startup.jl` startup script, nor do they synchronize +their global state (such as global variables, new method definitions, and loaded modules) with any +of the other running processes. You may use `addprocs(exeflags="--project")` to initialize a worker with +a particular environment, and then `@everywhere using ` or `@everywhere include("file.jl")`. 其它类型的集群可以通过自己写一个 `ClusterManager` 来实现,下面 [集群管理器](@ref) 部分会介绍。 @@ -979,7 +1002,7 @@ sent to the remote node to go ahead and remove its reference to the value. 一旦执行了 finalize 之后,引用就不可用了。 -## Local invocations(@id man-distributed-local-invocations) +## Local invocations Data is necessarily copied over to the remote node for execution. This is the case for both remotecalls and when data is stored to a[`RemoteChannel`](@ref) / [`Future`](@ref Distributed.Future) on @@ -1100,7 +1123,7 @@ julia> addprocs(3) julia> @everywhere using SharedArrays -julia> S = SharedArray{Int,2}((3,4), init = S -> S[localindices(S)] = myid()) +julia> S = SharedArray{Int,2}((3,4), init = S -> S[localindices(S)] = repeat([myid()], length(localindices(S)))) 3×4 SharedArray{Int64,2}: 2 2 3 4 2 3 3 4 @@ -1119,7 +1142,7 @@ julia> S [`SharedArrays.localindices`](@ref) 提供了一个以为的切片,可以很方便地用来将 task 分配到各个进程上。当然你可以按你想要的方式做区分: ```julia-repl -julia> S = SharedArray{Int,2}((3,4), init = S -> S[indexpids(S):length(procs(S)):length(S)] = myid()) +julia> S = SharedArray{Int,2}((3,4), init = S -> S[indexpids(S):length(procs(S)):length(S)] = repeat([myid()], length( indexpids(S):length(procs(S)):length(S)))) 3×4 SharedArray{Int64,2}: 2 2 2 2 3 3 3 3 diff --git a/zh_CN/doc/src/manual/performance-tips.md b/zh_CN/doc/src/manual/performance-tips.md index fb5d9c41..bceedcf3 100644 --- a/zh_CN/doc/src/manual/performance-tips.md +++ b/zh_CN/doc/src/manual/performance-tips.md @@ -126,7 +126,7 @@ the performance of your code: * [Profiling](@ref) allows you to measure the performance of your running code and identify lines that serve as bottlenecks. For complex projects, the [ProfileView](https://github.com/timholy/ProfileView.jl) package can help you visualize your profiling results. - * The [Traceur](https://github.com/MikeInnes/Traceur.jl) package can help you find common performance problems in your code. + * The [Traceur](https://github.com/JunoLab/Traceur.jl) package can help you find common performance problems in your code. * Unexpectedly-large memory allocations--as reported by [`@time`](@ref), [`@allocated`](@ref), or the profiler (through calls to the garbage-collection routines)--hint that there might be issues with your code. If you don't see another reason for the allocations, suspect a type problem. @@ -135,7 +135,7 @@ the performance of your code: * `@code_warntype` generates a representation of your code that can be helpful in finding expressions that result in type uncertainty. See [`@code_warntype`](@ref) below. -## Avoid containers with abstract type parameters +## [Avoid containers with abstract type parameters](@id man-performance-abstract-container) When working with parameterized types, including arrays, it is best to avoid parameterizing with abstract types where possible. @@ -424,6 +424,65 @@ c = (b + 1.0f0)::Complex{T} 不会降低性能(但也不会提高),因为编译器可以在编译 `k` 时确定 `c` 的类型。 +### Be aware of when Julia avoids specializing + +As a heuristic, Julia avoids automatically specializing on argument type parameters in three +specific cases: `Type`, `Function`, and `Vararg`. Julia will always specialize when the argument is +used within the method, but not if the argument is just passed through to another function. This +usually has no performance impact at runtime and +[improves compiler performance](@ref compiler-efficiency-issues). If you find it does have a +performance impact at runtime in your case, you can trigger specialization by adding a type +parameter to the method declaration. Here are some examples: + +This will not specialize: + +```julia +function f_type(t) # or t::Type + x = ones(t, 10) + return sum(map(sin, x)) +end +``` + +but this will: + +```julia +function g_type(t::Type{T}) where T + x = ones(T, 10) + return sum(map(sin, x)) +end +``` + +These will not specialize: + +```julia +f_func(f, num) = ntuple(f, div(num, 2)) +g_func(g::Function, num) = ntuple(g, div(num, 2)) +``` + +but this will: + +```julia +h_func(h::H, num) where {H} = ntuple(h, div(num, 2)) +``` + +This will not specialize: + +```julia +f_vararg(x::Int...) = tuple(x...) +``` + +but this will: + +```julia +g_vararg(x::Vararg{Int, N}) where {N} = tuple(x...) +``` + +Note that [`@code_typed`](@ref) and friends will always show you specialized code, even if Julia +would not normally specialize that method call. You need to check the +[method internals](@ref ast-lowered-method) if you want to see whether specializations are generated +when argument types are changed, i.e., if `(@which f(...)).specializations` contains specializations +for the argument in question. + ## 将函数拆分为多个定义 将一个函数写成许多小的定义能让编译器直接调用最适合的代码,甚至能够直接将它内联。 @@ -540,7 +599,7 @@ Julia 的编译器会在函数边界处针对参数类型特化代码,因此 诸如 `strange_twos` 的函数会在处理具有不确定类型的数据时出现,例如从可能包含整数、浮点数、字符串或其它内容的输入文件中加载的数据。 -## Types with values-as-parameters +## [Types with values-as-parameters](@id man-performance-value-type) 比方说你想创建一个每个维度大小都是3的 `N` 维数组。这种数组可以这样创建: @@ -668,7 +727,7 @@ or thousands of variants compiled for it. Each of these increases the size of th code, the length of internal lists of methods, etc. Excess enthusiasm for values-as-parameters can easily waste enormous resources. -## 按内存顺序访问数组,即按列访问 +## [Access arrays in memory order, along columns](@id man-performance-column-major) Julia 中的多维数组以列主序存储。这意味着数组一次堆叠一列。这可使用 `vec` 函数或语法 `[:]` 来验证,如下所示(请注意,数组的顺序是 `[1 3 2 4]`,而不是 `[1 2 3 4]`): @@ -977,7 +1036,9 @@ responses = [fetch(r) for r in refs] -使用 1:n 索引 AbstractArray 这一常见习惯在该数组使用非传统索引时是不安全的,并且在关闭边界检查时可能导致段错误。请改用 `LinearIndices(x)` 或 `eachindex(x)`(参阅 [offset-arrays](https://docs.julialang.org/en/latest/devdocs/offset-arrays/))。 +The common idiom of using 1:n to index into an AbstractArray is not safe if the Array uses unconventional indexing, +and may cause a segmentation fault if bounds checking is turned off. Use `LinearIndices(x)` or `eachindex(x)` +instead (see also [Arrays with custom indices](@ref man-custom-indices)). !!! note 虽然 `@simd` 需要直接放在最内层 `for` 循环前面,但 `@inbounds` 和 `@fastmath` 都可作用于单个表达式或在嵌套代码块中出现的所有表达式,例如,可使用 `@inbounds begin` 或 `@inbounds for ...`。 diff --git a/zh_CN/doc/src/manual/running-external-programs.md b/zh_CN/doc/src/manual/running-external-programs.md index 51114acd..65f106fb 100644 --- a/zh_CN/doc/src/manual/running-external-programs.md +++ b/zh_CN/doc/src/manual/running-external-programs.md @@ -269,7 +269,7 @@ pipeline(`do_work`, stdout=pipeline(`sort`, "out.txt"), stderr="errs.txt") ```julia writer = @async write(process, "data") reader = @async do_compute(read(process, String)) -wait(process) +wait(writer) fetch(reader) ``` diff --git a/zh_CN/doc/src/manual/stacktraces.md b/zh_CN/doc/src/manual/stacktraces.md index 0db527f4..98a1d523 100644 --- a/zh_CN/doc/src/manual/stacktraces.md +++ b/zh_CN/doc/src/manual/stacktraces.md @@ -286,4 +286,3 @@ julia> frame = StackTraces.lookup(pointer) julia> println("The top frame is from $(frame[1].func)!") The top frame is from jl_apply_generic! ``` - diff --git a/zh_CN/doc/src/manual/strings.md b/zh_CN/doc/src/manual/strings.md index 63cf6dfe..93d34971 100644 --- a/zh_CN/doc/src/manual/strings.md +++ b/zh_CN/doc/src/manual/strings.md @@ -68,7 +68,9 @@ julia> isvalid(Char, 0x110000) false ``` -目前,有效的 Unicode 代码为,从 `U+00` 至 `U+d7ff`,以及从 `U+e000` 至 `U+10ffff`。它们还未全部被赋予明确的含义,也还没必要被应用解释;然而,所有的这些值都被认为是有效的 Unicode 字符。 +As of this writing, the valid Unicode code points are `U+0000` through `U+D7FF` and `U+E000` through +`U+10FFFF`. These have not all been assigned intelligible meanings yet, nor are they necessarily +interpretable by applications, but all of these values are considered to be valid Unicode characters. 你可以在单引号中输入任何 Unicode 字符,通过使用 `\u` 加上至多 4 个十六进制数字或者 `\U` 加上至多 8 个十六进制数(最长的有效值也只需要 6 个): @@ -83,7 +85,7 @@ julia> '\u2200' '∀': Unicode U+2200 (category Sm: Symbol, math) julia> '\U10ffff' -'\U10ffff': Unicode U+10ffff (category Cn: Other, not assigned) +'\U10ffff': Unicode U+10FFFF (category Cn: Other, not assigned) ``` Julia 使用系统默认的区域和语言设置来确定,哪些字符可以被正确显示,哪些需要用 `\u` 或 `\U` 的转义来显示。除 Unicode 转义格式之外,还可以使用所有的[传统 C 语言转义输入形式](https://en.wikipedia.org/wiki/C_syntax#Backslash_escapes): @@ -139,23 +141,26 @@ julia> """Contains "quote" characters""" "Contains \"quote\" characters" ``` -如果想从字符串中提取字符, 可以通过索引字符串的方式来获取: +If you want to extract a character from a string, you index into it: ```jldoctest helloworldstring +julia> str[begin] +'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase) + julia> str[1] 'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase) julia> str[6] -',': ASCII/Unicode U+002c (category Po: Punctuation, other) +',': ASCII/Unicode U+002C (category Po: Punctuation, other) julia> str[end] -'\n': ASCII/Unicode U+000a (category Cc: Other, control) +'\n': ASCII/Unicode U+000A (category Cc: Other, control) ``` Many Julia objects, including strings, can be indexed with integers. The index of the first element (the first character of a string) is returned by [`firstindex(str)`](@ref), and the index of the last element (character) -with [`lastindex(str)`](@ref). The keyword `end` can be used inside an indexing -operation as shorthand for the last index along the given dimension. +with [`lastindex(str)`](@ref). The keywords `begin` and `end` can be used inside an indexing +operation as shorthand for the first and last indices, respectively, along the given dimension. String indexing, like most indexing in Julia, is 1-based: `firstindex` always returns `1` for any `AbstractString`. As we will see below, however, `lastindex(str)` is *not* in general the same as `length(str)` for a string, because some Unicode characters can occupy multiple "code units". @@ -164,16 +169,16 @@ because some Unicode characters can occupy multiple "code units". ```jldoctest helloworldstring julia> str[end-1] -'.': ASCII/Unicode U+002e (category Po: Punctuation, other) +'.': ASCII/Unicode U+002E (category Po: Punctuation, other) julia> str[end÷2] ' ': ASCII/Unicode U+0020 (category Zs: Separator, space) ``` -Using an index less than 1 or greater than `end` raises an error: +Using an index less than `begin` (`1`) or greater than `end` raises an error: ```jldoctest helloworldstring -julia> str[0] +julia> str[begin-1] ERROR: BoundsError: attempt to access String at index [0] [...] @@ -191,11 +196,11 @@ julia> str[4:9] "lo, wo" ``` -注意表达式 `str[k]` 和 `str[k:k]` 并没有给出相同的结果 +Notice that the expressions `str[k]` and `str[k:k]` do not give the same result: ```jldoctest helloworldstring julia> str[6] -',': ASCII/Unicode U+002c (category Po: Punctuation, other) +',': ASCII/Unicode U+002C (category Po: Punctuation, other) julia> str[6:6] "," @@ -380,7 +385,7 @@ julia> foreach(display, s) '\xc0\xa0': [overlong] ASCII/Unicode U+0020 (category Zs: Separator, space) '\xe2\x88': Malformed UTF-8 (category Ma: Malformed, bad data) '\xe2': Malformed UTF-8 (category Ma: Malformed, bad data) -'|': ASCII/Unicode U+007c (category Sm: Symbol, math) +'|': ASCII/Unicode U+007C (category Sm: Symbol, math) julia> isvalid.(collect(s)) 4-element BitArray{1}: @@ -393,7 +398,7 @@ julia> s2 = "\xf7\xbf\xbf\xbf" "\U1fffff" julia> foreach(display, s2) -'\U1fffff': Unicode U+1fffff (category In: Invalid, too high) +'\U1fffff': Unicode U+1FFFFF (category In: Invalid, too high) ``` 我们可以看到字符串 `s` 中的前两个代码单元形成了一个过长的空格字符编码。这是无效的,但是在字符串中作为单个字符是可以接受的。接下来的两个代码单元形成了一个有效的 3 位 UTF-8 序列开头。然而,第五个代码单元 `\xe2` 不是它的有效延续,所以代码单元 3 和 4 在这个字符串中也被解释为格式错误的字符。同理,由于 `|` 不是它的有效延续,代码单元 5 形成了一个格式错误的字符。最后字符串 `s2` 包含了一个太高的代码。 diff --git a/zh_CN/doc/src/manual/style-guide.md b/zh_CN/doc/src/manual/style-guide.md index 28787fa5..7bb5be84 100644 --- a/zh_CN/doc/src/manual/style-guide.md +++ b/zh_CN/doc/src/manual/style-guide.md @@ -62,7 +62,7 @@ foo(Int(x), Int(y)) 这里的关键在于,如果一个函数需要处理的是整数,强制让调用者来决定非整数如何被转换(比如说向下还是向上取整)会更好。同时,把类型声明得具体一些的话可以为以后的方法定义留有更多的空间。 -## 在会更改自身输入参数内容的函数名字后加 `!` +## [Append `!` to names of functions that modify their arguments](@id bang-convention) 如下的代码: @@ -146,7 +146,7 @@ a = Vector{Union{Int,AbstractString,Tuple,Array}}(undef, n) 7. **Value**. 对于关联集合来说,指的是键值对的值。 - 在类似于 `fill!(x, v)` 的情况中,指的是 `v`。 + In cases like [`fill!(x, v)`](@ref fill!), this is `v`. 8. **Everything else**. 任何的其它参数。 diff --git a/zh_CN/doc/src/manual/types.md b/zh_CN/doc/src/manual/types.md index 7b931d84..f879716a 100644 --- a/zh_CN/doc/src/manual/types.md +++ b/zh_CN/doc/src/manual/types.md @@ -83,7 +83,7 @@ end 此函数的返回值就像赋值给了一个类型已被声明的变量:返回值始终转换为`Float64`。 -## 抽象类型 +## [Abstract Types](@id man-abstract-types) 抽象类型不能实例化,只能作为类型图中的节点使用,从而描述由相关具体类型组成的集合:那些作为其后代的具体类型。我们从抽象类型开始,即使它们没有实例,因为它们是类型系统的主干:它们形成了概念的层次结构,这使得 Julia 的类型系统不只是对象实现的集合。 @@ -145,7 +145,10 @@ end 因此,抽象类型允许程序员编写泛型函数,之后可以通过许多具体类型的组合将其用作默认方法。多亏了多重分派,程序员可以完全控制是使用默认方法还是更具体的方法。 -需要注意的重点是,即使程序员依赖参数为抽象类型的函数,性能也不会有任何损失,因为它会针对每个调用它的参数元组的具体类型重新编译。(但在函数参数是抽象类型的容器的情况下,可能存在性能问题;请参阅[性能建议](@ref man-performance-tips)。) +An important point to note is that there is no loss in performance if the programmer relies on +a function whose arguments are abstract types, because it is recompiled for each tuple of argument +concrete types with which it is invoked. (There may be a performance issue, however, in the case +of function arguments that are containers of abstract types; see [Performance Tips](@ref man-performance-abstract-container).) ## 原始类型 @@ -1036,6 +1039,9 @@ julia> firstlast(Val(false)) 为了保证 Julia 的一致性,调用处应当始终传递 `Val` *实例*而不是*类型*,也就是使用 `foo(Val(:bar))` 而不是 `foo(Val{:bar})`。 -值得注意的是,参数「值」类型非常容易被误用,包括 `Val`;情况不太好时,你很容易使代码性能变得更*糟糕*。一般使用时,你可能从来不会想要写出上方示例那样的代码。有关 `Val` 的正确(和不正确)使用的更多信息,请阅读[性能建议](@ref man-performance-tips)中更广泛的讨论。 +It's worth noting that it's extremely easy to mis-use parametric "value" types, including `Val`; +in unfavorable cases, you can easily end up making the performance of your code much *worse*. + In particular, you would never want to write actual code as illustrated above. For more information +about the proper (and improper) uses of `Val`, please read [the more extensive discussion in the performance tips](@ref man-performance-value-type). [^1]: 「少数」由常数 `MAX_UNION_SPLITTING` 定义,目前设置为 4。 diff --git a/zh_CN/doc/src/manual/variables-and-scoping.md b/zh_CN/doc/src/manual/variables-and-scoping.md index 9914b194..7571b89e 100644 --- a/zh_CN/doc/src/manual/variables-and-scoping.md +++ b/zh_CN/doc/src/manual/variables-and-scoping.md @@ -236,7 +236,11 @@ julia> counter() 2 ``` -也可以参见接下来两节例子中的闭包。内部函数从包含它的作用域中继承的变量有时被称为*被捕获*变量,比如在第一个例子中的 `x` 与在第二个例子中的 `state`。被捕获变量可能带来性能挑战,这会在[性能建议](@ref man-performance-tips)中讨论。 +See also the closures in the examples in the next two sections. A variable, +such as `x` in the first example and `state` in the second, that is inherited +from the enclosing scope by the inner function is sometimes called a +*captured* variable. Captured variables can present [performance challenges +discussed in performance tips](@ref man-performance-captured). 继承全局作用域与嵌套局部作用域的区别可能导致在局部或者全局作用域中定义的函数在变量赋值上有稍许区别。考虑一下上面最后一个例子的一个变化,把 `bar` 移动到全局作用域中: @@ -363,7 +367,9 @@ julia> let ### 对于循环和推导式 -`for` 循环,`while` 循环,和[数组推导](@ref)拥有下述的行为:任何在它们的内部的作用域中引入的新变量在每次循环迭代中都会被新分配一块内存,就像循环体是被 `let` 块包围一样。 +`for` loops, `while` loops, and [comprehensions](@ref man-comprehensions) have the following behavior: any new variables +introduced in their body scopes are freshly allocated for each loop iteration, as if the loop body +were surrounded by a `let` block: ```jldoctest julia> Fs = Vector{Any}(undef, 2); diff --git a/zh_CN/doc/src/manual/variables.md b/zh_CN/doc/src/manual/variables.md index f0200a54..505d2125 100644 --- a/zh_CN/doc/src/manual/variables.md +++ b/zh_CN/doc/src/manual/variables.md @@ -1,4 +1,4 @@ -# 变量 +# [Variables](@id man-variables) Julia 语言中,变量是与某个值相关联(或绑定)的名字。你可以用它来保存一个值(例如某些计算得到的结果),供之后的代码使用。例如: From 33df464bb1c1219781536013096c4866f8c29e78 Mon Sep 17 00:00:00 2001 From: Rogerluo Date: Thu, 18 Jun 2020 11:22:55 -0400 Subject: [PATCH 2/4] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c0f8e3f5..ec18c842 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "JuliaZH" uuid = "652e05fd-ed22-5b6c-bf99-44e63a676e5f" -version = "1.1.0" +version = "1.4.0" [deps] REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" From 92af0537adfe49cfd6e7b38af340e1ae6c0c4470 Mon Sep 17 00:00:00 2001 From: Rogerluo Date: Thu, 18 Jun 2020 11:55:32 -0400 Subject: [PATCH 3/4] Update index.md --- doc/src/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/index.md b/doc/src/index.md index bd47f845..d480e6e9 100644 --- a/doc/src/index.md +++ b/doc/src/index.md @@ -1,6 +1,6 @@ -# Julia 1.1 中文文档 +# Julia 1.4 中文文档 -欢迎来到 Julia 1.1 中文文档([PDF版本](https://raw.githubusercontent.com/JuliaCN/JuliaZH.jl/pdf/dev/Julia中文文档.pdf))! +欢迎来到 Julia 1.4 中文文档([PDF版本](https://raw.githubusercontent.com/JuliaCN/JuliaZH.jl/pdf/dev/Julia中文文档.pdf))! 请先阅读 [v1.0 正式发布博文](https://julialang.org/blog/2018/08/one-point-zero-zh_cn) 以获得对这门语言的总体概观。我们推荐刚刚开始学习 Julia 语言的朋友阅读中文社区提供的 [Julia入门指引](https://discourse.juliacn.com/t/topic/159),也推荐你使用[discourse](https://discourse.juliacn.com)对遇到的问题进行提问。 From f9005ab72d6d5c892e1020c6ed7cb7106fceaa10 Mon Sep 17 00:00:00 2001 From: Rogerluo Date: Thu, 18 Jun 2020 12:06:13 -0400 Subject: [PATCH 4/4] Update index.md --- doc/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/index.md b/doc/src/index.md index d480e6e9..b6988b4c 100644 --- a/doc/src/index.md +++ b/doc/src/index.md @@ -1,6 +1,6 @@ # Julia 1.4 中文文档 -欢迎来到 Julia 1.4 中文文档([PDF版本](https://raw.githubusercontent.com/JuliaCN/JuliaZH.jl/pdf/dev/Julia中文文档.pdf))! +欢迎来到 Julia 1.4 中文文档([PDF版本](https://raw.githubusercontent.com/JuliaCN/JuliaZH.jl/pdf/v1.4.0/Julia中文文档-1.4.0.pdf))! 请先阅读 [v1.0 正式发布博文](https://julialang.org/blog/2018/08/one-point-zero-zh_cn) 以获得对这门语言的总体概观。我们推荐刚刚开始学习 Julia 语言的朋友阅读中文社区提供的 [Julia入门指引](https://discourse.juliacn.com/t/topic/159),也推荐你使用[discourse](https://discourse.juliacn.com)对遇到的问题进行提问。