Julia快速入門(3)

lt發表於2017-03-27

轉載自:X分鐘速成Y其中 Y=Julia
原始碼下載learn-julia-zh.jl

####################################################
## 6. 多分派
####################################################

# 在Julia中, 所有的具名函式都是類屬函式
# 這意味著他們都是有很大小方法組成的
# 每個 Lion 的建構函式都是類屬函式 Lion 的方法

# 我們來看一個非建構函式的例子

# Lion, Panther, Tiger 的 meow 定義為
function meow(animal::Lion)
  animal.roar # 使用點符號訪問屬性
end

function meow(animal::Panther)
  "grrr"
end

function meow(animal::Tiger)
  "rawwwr"
end

# 試試 meow 函式
meow(tigger) # => "rawwr"
meow(Lion("brown","ROAAR")) # => "ROAAR"
meow(Panther()) # => "grrr"

# 再看看層次結構
issubtype(Tiger,Cat) # => false
issubtype(Lion,Cat) # => true
issubtype(Panther,Cat) # => true

# 定義一個接收 Cats 的函式
function pet_cat(cat::Cat)
  println("The cat says $(meow(cat))")
end

pet_cat(Lion("42")) # => prints "The cat says 42"
try
    pet_cat(tigger) # => ERROR: no method pet_cat(Tiger,)
catch e
    println(e)
end

# 在面嚮物件語言中,通常都是單分派
# 這意味著分派方法是通過第一個引數的型別決定的
# 在Julia中, 所有引數型別都會被考慮到

# 讓我們定義有多個引數的函式,好看看區別
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!

# 讓我們修改一下傳入具體為 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!

# 把 Tiger 去掉
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
try
  fight(Panther(),Lion("RAWR")) # => ERROR: no method fight(Panther,Lion)
catch
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)

# 警告說明了無法判斷使用哪個 fight 方法
fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The victorious cat says rarrr
# 結果在老版本 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


# Under the hood
# 你還可以看看 llvm 以及生成的彙編程式碼

square_area(l) = l * l      # square_area (generic function with 1 method)

square_area(5) #25

# 給 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

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

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 就使用浮點指令
# 讓我們計算一下圓的面積
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
    #

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
    #

相關文章