diff options
| author | 0u0 <inkydragon@users.noreply.github.com> | 2018-08-31 07:55:10 +0800 | 
|---|---|---|
| committer | 0u0 <inkydragon@users.noreply.github.com> | 2018-08-31 07:55:10 +0800 | 
| commit | 207e16a93181e1ccf057a04ca4e1a1a1e2d59491 (patch) | |
| tree | 62d2ec4335ec529975ac46a9a4a08f9e3c0414a2 | |
| parent | efd37d969547b5a2a9beaa0a874364b24a8f6e4d (diff) | |
Update to Julia 1.0 (Finish 6/6)
| -rw-r--r-- | zh-cn/julia-cn.html.markdown | 479 | 
1 files changed, 272 insertions, 207 deletions
| diff --git a/zh-cn/julia-cn.html.markdown b/zh-cn/julia-cn.html.markdown index f9c68eb6..35c2e2d4 100644 --- a/zh-cn/julia-cn.html.markdown +++ b/zh-cn/julia-cn.html.markdown @@ -336,7 +336,6 @@ intersect(filled_set, other_set)      # => Set([4, 3, 5])  union(filled_set, other_set)          # => Set([4, 2, 3, 5, 6, 1])  setdiff(Set([1,2,3,4]), Set([2,3,5])) # => Set([4, 1]) -  ####################################################  ## 3. 控制语句  #################################################### @@ -409,81 +408,88 @@ catch e  end  # => caught it ErrorException("help") -  ####################################################  ## 4. 函数  #################################################### -# 用关键字 'function' 可创建一个新函数 -#function name(arglist) -#  body... -#end +# 关键字 'function' 用于定义函数 +# function name(arglist) +#   body... +# end  function add(x, y)      println("x is $x and y is $y") -    # 最后一行语句的值为返回 +    # 函数会返回最后一行的值      x + y  end -add(5, 6) # => 在 "x is 5 and y is 6" 后会打印 11 +add(5, 6) +# => x is 5 and y is 6 +# => 11 + +# 更紧凑的定义函数 +f_add(x, y) = x + y  # => f_add (generic function with 1 method) +f_add(3, 4)  # => 7 + +# 函数可以将多个值作为元组返回 +fn(x, y) = x + y, x - y # => fn (generic function with 1 method) +fn(3, 4)  # => (7, -1)  # 还可以定义接收可变长参数的函数  function varargs(args...)      return args -    # 关键字 return 可在函数内部任何地方返回 +    # 使用 return 可以在函数内的任何地方返回  end  # => varargs (generic function with 1 method)  varargs(1,2,3) # => (1,2,3) -# 省略号 ... 被称为 splat. +# 省略号 ... 称为 splat  # 刚刚用在了函数定义中 -# 还可以用在函数的调用 -# Array 或者 Tuple 的内容会变成参数列表 -Set([1,2,3])    # => Set{Array{Int64,1}}([1,2,3]) # 获得一个 Array 的 Set -Set([1,2,3]...) # => Set{Int64}(1,2,3) # 相当于 Set(1,2,3) - -x = (1,2,3)     # => (1,2,3) -Set(x)          # => Set{(Int64,Int64,Int64)}((1,2,3)) # 一个 Tuple 的 Set -Set(x...)       # => Set{Int64}(2,3,1) +# 在调用函数时也可以使用它,此时它会把数组或元组解包为参数列表 +add([5,6]...)  # 等价于 add(5,6) +x = (5, 6)  # => (5,6) +add(x...)  # 等价于 add(5,6) -# 可定义可选参数的函数 -function defaults(a,b,x=5,y=6) +# 可定义带可选参数的函数 +function defaults(a, b, x=5, y=6)      return "$a $b and $x $y"  end +# => defaults (generic function with 3 methods) -defaults('h','g') # => "h g and 5 6" -defaults('h','g','j') # => "h g and j 6" -defaults('h','g','j','k') # => "h g and j k" +defaults('h', 'g')  # => "h g and 5 6" +defaults('h', 'g', 'j')  # => "h g and j 6" +defaults('h', 'g', 'j', 'k')  # => "h g and j k"  try -    defaults('h') # => ERROR: no method defaults(Char,) -    defaults() # => ERROR: no methods defaults() +    defaults('h')  # => ERROR: MethodError: no method matching defaults(::Char) +    defaults()  # => ERROR: MethodError: no method matching defaults()  catch e      println(e)  end -# 还可以定义键值对的参数 -function keyword_args(;k1=4,name2="hello") # note the ; -    return ["k1"=>k1,"name2"=>name2] +# 还可以定义带关键字参数的函数 +function keyword_args(;k1=4, name2="hello")  # 注意分号 ';' +    return Dict("k1" => k1, "name2" => name2)  end +# => keyword_args (generic function with 1 method) -keyword_args(name2="ness") # => ["name2"=>"ness","k1"=>4] -keyword_args(k1="mine") # => ["k1"=>"mine","name2"=>"hello"] -keyword_args() # => ["name2"=>"hello","k1"=>4] +keyword_args(name2="ness")  # => ["name2"=>"ness", "k1"=>4] +keyword_args(k1="mine")     # => ["name2"=>"hello", "k1"=>"mine"] +keyword_args()              # => ["name2"=>"hello", "k1"=>4] -# 可以组合各种类型的参数在同一个函数的参数列表中 +# 可以在一个函数中组合各种类型的参数  function all_the_args(normal_arg, optional_positional_arg=2; keyword_arg="foo")      println("normal arg: $normal_arg")      println("optional arg: $optional_positional_arg")      println("keyword arg: $keyword_arg")  end +# => all_the_args (generic function with 2 methods)  all_the_args(1, 3, keyword_arg=4) -# prints: -#   normal arg: 1 -#   optional arg: 3 -#   keyword arg: 4 +# => normal arg: 1 +# => optional arg: 3 +# => keyword arg: 4  # Julia 有一等函数  function create_adder(x) @@ -492,14 +498,16 @@ function create_adder(x)      end      return adder  end +# => create_adder (generic function with 1 method)  # 这是用 "stabby lambda syntax" 创建的匿名函数  (x -> x > 2)(3) # => true -# 这个函数和上面的 create_adder 一模一样 +# 这个函数和上面的 create_adder 是等价的  function create_adder(x)      y -> x + y  end +# => create_adder (generic function with 1 method)  # 你也可以给内部函数起个名字  function create_adder(x) @@ -508,18 +516,19 @@ function create_adder(x)      end      adder  end +# => create_adder (generic function with 1 method) -add_10 = create_adder(10) -add_10(3) # => 13 - +add_10 = create_adder(10) # => (::getfield(Main, Symbol("#adder#11")){Int64})  +                          # (generic function with 1 method) +add_10(3)  # => 13  # 内置的高阶函数有 -map(add_10, [1,2,3]) # => [11, 12, 13] -filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7] +map(add_10, [1,2,3])  # => [11, 12, 13] +filter(x -> x > 5, [3, 4, 5, 6, 7])  # => [6, 7] -# 还可以使用 list comprehensions 替代 map -[add_10(i) for i=[1, 2, 3]] # => [11, 12, 13] -[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] +# 还可以使用 list comprehensions 让 map 更美观 +[add_10(i) for i = [1, 2, 3]]   # => [11, 12, 13] +[add_10(i) for i in [1, 2, 3]]  # => [11, 12, 13]  ####################################################  ## 5.  类型 @@ -531,248 +540,304 @@ filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7]  typeof(5) # => Int64  # 类型是一等值 -typeof(Int64) # => DataType -typeof(DataType) # => DataType +typeof(Int64)     # => DataType +typeof(DataType)  # => DataType  # DataType 是代表类型的类型,也代表他自己的类型 -# 类型可用作文档化,优化,以及调度 -# 并不是静态检查类型 +# 类型可用于文档化代码、执行优化以及多重派分(dispatch) +# Julia 并不只是静态的检查类型  # 用户还可以自定义类型 -# 跟其他语言的 records 或 structs 一样 -# 用 `type` 关键字定义新的类型 +# 就跟其它语言的 records 或 structs 一样 +# 用 `struct` 关键字定义新的类型 -# type Name +# struct Name  #   field::OptionalType  #   ...  # end -type Tiger -  taillength::Float64 -  coatcolor # 不附带类型标注的相当于 `::Any` +struct Tiger +    taillength::Float64 +    coatcolor  # 不带类型标注相当于 `::Any`  end -# 构造函数参数是类型的属性 -tigger = Tiger(3.5,"orange") # => Tiger(3.5,"orange") +# 默认构造函数的参数是类型的属性,按类型定义中的顺序排列 +tigger = Tiger(3.5, "orange")  # => Tiger(3.5, "orange")  # 用新类型作为构造函数还会创建一个类型 -sherekhan = typeof(tigger)(5.6,"fire") # => Tiger(5.6,"fire") +sherekhan = typeof(tigger)(5.6, "fire")  # => Tiger(5.6, "fire") -# struct 类似的类型被称为具体类型 -# 他们可被实例化但不能有子类型 +# 类似 struct 的类型被称为具体类型 +# 它们可被实例化,但不能有子类型  # 另一种类型是抽象类型 -# abstract Name -abstract Cat # just a name and point in the type hierarchy +# 抽象类型名 +abstract type Cat end  # 仅仅是指向类型结构层次的一个名称 -# 抽象类型不能被实例化,但是可以有子类型 +# 抽象类型不能被实例化,但可以有子类型  # 例如,Number 就是抽象类型 -subtypes(Number) # => 6-element Array{Any,1}: -                 #     Complex{Float16} -                 #     Complex{Float32} -                 #     Complex{Float64} -                 #     Complex{T<:Real} -                 #     ImaginaryUnit -                 #     Real -subtypes(Cat) # => 0-element Array{Any,1} - -# 所有的类型都有父类型; 可以用函数 `super` 得到父类型. +subtypes(Number)  # => 2-element Array{Any,1}: +                  # =>  Complex +                  # =>  Real +subtypes(Cat)  # => 0-element Array{Any,1} + +# AbstractString,类如其名,也是一个抽象类型 +subtypes(AbstractString)  # => 4-element Array{Any,1}: +                          # =>  String +                          # =>  SubString +                          # =>  SubstitutionString +                          # =>  Test.GenericString + +# 所有的类型都有父类型。可以用函数 `supertype` 得到父类型  typeof(5) # => Int64 -super(Int64) # => Signed -super(Signed) # => Real -super(Real) # => Number -super(Number) # => Any -super(super(Signed)) # => Number -super(Any) # => Any -# 所有这些类型,除了 Int64, 都是抽象类型. - -# <: 是类型集成操作符 -type Lion <: Cat # Lion 是 Cat 的子类型 -  mane_color -  roar::String +supertype(Int64)    # => Signed +supertype(Signed)   # => Integer +supertype(Integer)  # => Real +supertype(Real)     # => Number +supertype(Number)   # => Any +supertype(supertype(Signed))  # => Real +supertype(Any)      # => Any +# 除了 Int64 外,其余的类型都是抽象类型 +typeof("fire")      # => String +supertype(String)   # => AbstractString +supertype(AbstractString) # => Any +supertype(SubString)  # => AbstractString + +# <: 是子类型化操作符 +struct Lion <: Cat  # Lion 是 Cat 的子类型 +    mane_color +    roar::AbstractString  end  # 可以继续为你的类型定义构造函数 -# 只需要定义一个同名的函数 -# 并调用已有的构造函数设置一个固定参数 -Lion(roar::String) = Lion("green",roar) -# 这是一个外部构造函数,因为他再类型定义之外 - -type Panther <: Cat # Panther 也是 Cat 的子类型 -  eye_color -  Panther() = new("green") -  # Panthers 只有这个构造函数,没有默认构造函数 +# 只需要定义一个与类型同名的函数,并调用已有的构造函数得到正确的类型 +Lion(roar::AbstractString) = Lion("green", roar)  # => Lion +# 这是一个外部构造函数,因为它在类型定义之外 + +struct Panther <: Cat # Panther 也是 Cat 的子类型 +    eye_color +    Panther() = new("green") +    # Panthers 只有这个构造函数,没有默认构造函数  end -# 使用内置构造函数,如 Panther,可以让你控制 -# 如何构造类型的值 -# 应该尽可能使用外部构造函数而不是内部构造函数 +# 像 Panther 一样使用内置构造函数,让你可以控制如何构建类型的值 +# 应该尽量使用外部构造函数,而不是内部构造函数  ####################################################  ## 6. 多分派  #################################################### -# 在Julia中, 所有的具名函数都是类属函数 -# 这意味着他们都是有很大小方法组成的 -# 每个 Lion 的构造函数都是类属函数 Lion 的方法 +# Julia 中所有的函数都是通用函数,或者叫做泛型函数(generic functions) +# 也就是说这些函数都是由许多小方法组合而成的 +# Lion 的每一种构造函数都是通用函数 Lion 的一个方法  # 我们来看一个非构造函数的例子 +# 首先,让我们定义一个函数 meow -# Lion, Panther, Tiger 的 meow 定义为 +# Lion, Panther, Tiger 的 meow 定义分别为  function meow(animal::Lion) -  animal.roar # 使用点符号访问属性 +    animal.roar # 使用点记号 '.' 访问属性  end  function meow(animal::Panther) -  "grrr" +    "grrr"  end  function meow(animal::Tiger) -  "rawwwr" +    "rawwwr"  end  # 试试 meow 函数 -meow(tigger) # => "rawwr" -meow(Lion("brown","ROAAR")) # => "ROAAR" +meow(tigger)  # => "rawwwr" +meow(Lion("brown", "ROAAR"))  # => "ROAAR"  meow(Panther()) # => "grrr" -# 再看看层次结构 -issubtype(Tiger,Cat) # => false -issubtype(Lion,Cat) # => true -issubtype(Panther,Cat) # => true +# 回顾类型的层次结构 +Tiger <: Cat    # => false +Lion <: Cat     # => true +Panther <: Cat  # => true -# 定义一个接收 Cats 的函数 +# 定义一个接收 Cat 类型的函数  function pet_cat(cat::Cat) -  println("The cat says $(meow(cat))") +    println("The cat says $(meow(cat))")  end +# => pet_cat (generic function with 1 method) -pet_cat(Lion("42")) # => prints "The cat says 42" +pet_cat(Lion("42"))  # => The cat says 42  try -    pet_cat(tigger) # => ERROR: no method pet_cat(Tiger,) +    pet_cat(tigger)  # => ERROR: MethodError: no method matching pet_cat(::Tiger)  catch e      println(e)  end  # 在面向对象语言中,通常都是单分派 -# 这意味着分派方法是通过第一个参数的类型决定的 -# 在Julia中, 所有参数类型都会被考虑到 +# 这意味着使用的方法取决于第一个参数的类型 +# 而 Julia 中选择方法时会考虑到所有参数的类型 -# 让我们定义有多个参数的函数,好看看区别 -function fight(t::Tiger,c::Cat) -  println("The $(t.coatcolor) tiger wins!") +# 让我们定义一个有更多参数的函数,这样我们就能看出区别 +function fight(t::Tiger, c::Cat) +    println("The $(t.coatcolor) tiger wins!")  end  # => fight (generic function with 1 method) -fight(tigger,Panther()) # => prints The orange tiger wins! -fight(tigger,Lion("ROAR")) # => prints The orange tiger wins! +fight(tigger, Panther())  # => The orange tiger wins! +fight(tigger, Lion("ROAR")) # => fight(tigger, Lion("ROAR")) -# 让我们修改一下传入具体为 Lion 类型时的行为 -fight(t::Tiger,l::Lion) = println("The $(l.mane_color)-maned lion wins!") +# 让我们修改一下传入 Lion 类型时的行为 +fight(t::Tiger, l::Lion) = println("The $(l.mane_color)-maned lion wins!")  # => fight (generic function with 2 methods) -fight(tigger,Panther()) # => prints The orange tiger wins! -fight(tigger,Lion("ROAR")) # => prints The green-maned lion wins! +fight(tigger, Panther())  # => The orange tiger wins! +fight(tigger, Lion("ROAR"))  # => The green-maned lion wins! -# 把 Tiger 去掉 -fight(l::Lion,c::Cat) = println("The victorious cat says $(meow(c))") +# 我们不需要一只老虎参与战斗 +fight(l::Lion, c::Cat) = println("The victorious cat says $(meow(c))")  # => fight (generic function with 3 methods) -fight(Lion("balooga!"),Panther()) # => prints The victorious cat says grrr +fight(Lion("balooga!"), Panther())  # => The victorious cat says grrr  try -  fight(Panther(),Lion("RAWR")) # => ERROR: no method fight(Panther,Lion) -catch +    fight(Panther(), Lion("RAWR"))   +    # => ERROR: MethodError: no method matching fight(::Panther, ::Lion) +    # => Closest candidates are: +    # =>   fight(::Tiger, ::Lion) at ... +    # =>   fight(::Tiger, ::Cat) at ... +    # =>   fight(::Lion, ::Cat) at ... +    # => ... +catch e +    println(e)  end -# 在试试让 Cat 在前面 -fight(c::Cat,l::Lion) = println("The cat beats the Lion") -# => Warning: New definition -#    fight(Cat,Lion) at none:1 -# is ambiguous with -#    fight(Lion,Cat) at none:2. -# Make sure -#    fight(Lion,Lion) -# is defined first. -#fight (generic function with 4 methods) +# 试试把 Cat 放在前面 +fight(c::Cat, l::Lion) = println("The cat beats the Lion") +# => fight (generic function with 4 methods) -# 警告说明了无法判断使用哪个 fight 方法 -fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The victorious cat says rarrr -# 结果在老版本 Julia 中可能会不一样 +# 由于无法判断该使用哪个 fight 方法,而产生了错误 +try +    fight(Lion("RAR"), Lion("brown", "rarrr")) +    # => ERROR: MethodError: fight(::Lion, ::Lion) is ambiguous. Candidates: +    # =>   fight(c::Cat, l::Lion) in Main at ... +    # =>   fight(l::Lion, c::Cat) in Main at ... +    # => Possible fix, define +    # =>   fight(::Lion, ::Lion) +    # => ... +catch e +    println(e) +end +# 在不同版本的 Julia 中错误信息可能有所不同 -fight(l::Lion,l2::Lion) = println("The lions come to a tie") -fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The lions come to a tie +fight(l::Lion, l2::Lion) = println("The lions come to a tie")  +# => fight (generic function with 5 methods) +fight(Lion("RAR"), Lion("brown", "rarrr"))  # => The lions come to a tie  # Under the hood -# 你还可以看看 llvm 以及生成的汇编代码 - -square_area(l) = l * l      # square_area (generic function with 1 method) +# 你还可以看看 llvm 以及它生成的汇编代码 -square_area(5) #25 +square_area(l) = l * l  # => square_area (generic function with 1 method) +square_area(5)  # => 25 -# 给 square_area 一个整形时发生什么 +# 当我们喂给 square_area 一个整数时会发生什么?  code_native(square_area, (Int32,)) -    #       .section    __TEXT,__text,regular,pure_instructions -    #   Filename: none -    #   Source line: 1              # Prologue -    #       push    RBP -    #       mov RBP, RSP -    #   Source line: 1 -    #       movsxd  RAX, EDI        # Fetch l from memory? -    #       imul    RAX, RAX        # Square l and store the result in RAX -    #       pop RBP                 # Restore old base pointer -    #       ret                     # Result will still be in RAX +    #         .text +    # ; Function square_area { +    # ; Location: REPL[49]:1 +    #         pushq   %rbp +    #         movq    %rsp, %rbp +    # ; Function *; { +    # ; Location: int.jl:54 +    #         imull   %ecx, %ecx +    # ;} +    #         movl    %ecx, %eax +    #         popq    %rbp +    #         retq +    #         nopl    (%rax,%rax) +    # ;}  code_native(square_area, (Float32,)) -    #       .section    __TEXT,__text,regular,pure_instructions -    #   Filename: none -    #   Source line: 1 -    #       push    RBP -    #       mov RBP, RSP -    #   Source line: 1 -    #       vmulss  XMM0, XMM0, XMM0  # Scalar single precision multiply (AVX) -    #       pop RBP -    #       ret +    #         .text +    # ; Function square_area { +    # ; Location: REPL[49]:1 +    #         pushq   %rbp +    #         movq    %rsp, %rbp +    # ; Function *; { +    # ; Location: float.jl:398 +    #         vmulss  %xmm0, %xmm0, %xmm0 +    # ;} +    #         popq    %rbp +    #         retq +    #         nopw    (%rax,%rax) +    # ;}  code_native(square_area, (Float64,)) -    #       .section    __TEXT,__text,regular,pure_instructions -    #   Filename: none -    #   Source line: 1 -    #       push    RBP -    #       mov RBP, RSP -    #   Source line: 1 -    #       vmulsd  XMM0, XMM0, XMM0 # Scalar double precision multiply (AVX) -    #       pop RBP -    #       ret -    # -# 注意 只要参数中又浮点类型,Julia 就使用浮点指令 +    #         .text +    # ; Function square_area { +    # ; Location: REPL[49]:1 +    #         pushq   %rbp +    #         movq    %rsp, %rbp +    # ; Function *; { +    # ; Location: float.jl:399 +    #         vmulsd  %xmm0, %xmm0, %xmm0 +    # ;} +    #         popq    %rbp +    #         retq +    #         nopw    (%rax,%rax) +    # ;} + +# 注意!只要参数中有浮点数,Julia 就会使用浮点指令  # 让我们计算一下圆的面积 -circle_area(r) = pi * r * r     # circle_area (generic function with 1 method) -circle_area(5)                  # 78.53981633974483 +circle_area(r) = pi * r * r # => circle_area (generic function with 1 method) +circle_area(5)  # => 78.53981633974483  code_native(circle_area, (Int32,)) -    #       .section    __TEXT,__text,regular,pure_instructions -    #   Filename: none -    #   Source line: 1 -    #       push    RBP -    #       mov RBP, RSP -    #   Source line: 1 -    #       vcvtsi2sd   XMM0, XMM0, EDI          # Load integer (r) from memory -    #       movabs  RAX, 4593140240              # Load pi -    #       vmulsd  XMM1, XMM0, QWORD PTR [RAX]  # pi * r -    #       vmulsd  XMM0, XMM0, XMM1             # (pi * r) * r -    #       pop RBP -    #       ret -    # +    #         .text +    # ; Function circle_area { +    # ; Location: REPL[53]:1 +    #         pushq   %rbp +    #         movq    %rsp, %rbp +    # ; Function *; { +    # ; Location: operators.jl:502 +    # ; Function *; { +    # ; Location: promotion.jl:314 +    # ; Function promote; { +    # ; Location: promotion.jl:284 +    # ; Function _promote; { +    # ; Location: promotion.jl:261 +    # ; Function convert; { +    # ; Location: number.jl:7 +    # ; Function Type; { +    # ; Location: float.jl:60 +    #         vcvtsi2sdl      %ecx, %xmm0, %xmm0 +    #         movabsq $532051920, %rax        # imm = 0x1FB677D0 +    # ;}}}}} +    # ; Function *; { +    # ; Location: float.jl:399 +    #         vmulsd  (%rax), %xmm0, %xmm1 +    #         vmulsd  %xmm0, %xmm1, %xmm0 +    # ;}} +    #         popq    %rbp +    #         retq +    #         nopl    (%rax) +    # ;}  code_native(circle_area, (Float64,)) -    #       .section    __TEXT,__text,regular,pure_instructions -    #   Filename: none -    #   Source line: 1 -    #       push    RBP -    #       mov RBP, RSP -    #       movabs  RAX, 4593140496 -    #   Source line: 1 -    #       vmulsd  XMM1, XMM0, QWORD PTR [RAX] -    #       vmulsd  XMM0, XMM1, XMM0 -    #       pop RBP -    #       ret -    # +    #         .text +    # ; Function circle_area { +    # ; Location: REPL[53]:1 +    #         pushq   %rbp +    #         movq    %rsp, %rbp +    #         movabsq $532052040, %rax        # imm = 0x1FB67848 +    # ; Function *; { +    # ; Location: operators.jl:502 +    # ; Function *; { +    # ; Location: promotion.jl:314 +    # ; Function *; { +    # ; Location: float.jl:399 +    #         vmulsd  (%rax), %xmm0, %xmm1 +    # ;}}} +    # ; Function *; { +    # ; Location: float.jl:399 +    #         vmulsd  %xmm0, %xmm1, %xmm0 +    # ;} +    #         popq    %rbp +    #         retq +    #         nopl    (%rax,%rax) +    # ;}  ``` | 
