Julia體驗 語言基礎


以前聽說過Julia,不過那時候官網還處於時不時宕機狀態,最近Julia發布了1.0 released版本到處都是它的資訊,官網良心自帶簡體中文,趁着熱度我也來試試,順便聊記一二。

關於Julia

Julia源於用戶需求。用戶希望有一門開源的腳本編程語言,有C的高性能,Ruby的靈活,Lisp的宏,Matlab那樣親切的數學表達式符號。它既可以像Python一樣作為通用編程語言,也可以像R一樣用於統計分析,像Perl一樣自然的處理字符串,像Matlab一樣強大的線性代數,像Shell一樣的膠着其他程序。
簡而言之,它什么都想,什么都像...
官方給出的Julia有以下特性(省略了一些):

  • 快速:Julia可以通過LLVM而跨平台被編譯成高效的本地代碼。
  • 通用:Julia使用多分派作為編程范式,使其很容易表達面向對象和函數式編程范式。
  • 動態:Julia是動態類型的,與腳本語言類似
  • 數值計算:Julia擅長於數值計算,它的語法適用於數學計算,支持多種數值類型,並且支持並行計算。
  • 可選的類型標注:Julia擁有豐富的數據類型描述
  • 可組合:Julia的包可以很自然的組合運行。單位數量的矩陣或數據表一列中的貨幣和顏色可以一起組合使用並且擁有良好的性能。

變量和字符串

Julia內建支持大數運算,不需要調用函數。同時也支持unicode

julia> 83275689127389671289376897238976*895623897689127389068912376897289/3487689234768972893+28358923785-23895728937
-3.4911515696355016e18

julia> unicode_var = "你好,中國"
"你好,中國"

julia> 'g'
'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)

julia> λ =  "special_variable_name"
"special_variable_name"

julia> λ =  "redefine its value since it's a variable"
"redefine its value since it's a variable"

字符串會處理轉義字符,如果想保留它們需要在前面加上raw

julia> println("hello\nworld")
hello
world

julia> println(raw"hello\nworld")
hello\nworld

還可以通過下標運算取到對應字符,最后一個字符用end指代,這但是下標居然不是從0開始的!

julia> welcome[0]
ERROR: BoundsError: attempt to access "hello world"
  at index [0]

julia> welcome[1]
  'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase)

julia> welcome[end]
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)

還可以使用切片操作welcome[2:4]獲取子字符串ello
拼接字符串需要用string(str1,str2.,..)或者*,不能使用+

如果要對字符串進行內部求值(官方術語interpolation),需要使用$(xx)的語法:

julia> "3+2-5=$(3+2-5)"
"3+2-5=0"

julia> name = "yang"
"yang"

julia> "hello, $name"
"hello, yang"

Julia目標稱希望有Perl一樣強大的字符串處理能力,那么內建正則表達式算是言出必行的表現。它的正則表達式是Perl兼容的,由PCRE提供,下面示例來自官方文檔:

julia> r"^\s*(?:#|$)"
r"^\s*(?:#|$)"

julia> typeof(ans)
Regex

julia> m = match(r"(a|b)(c)?(d)", "acd")
RegexMatch("acd", 1="a", 2="c", 3="d")

julia> m.match
"acd"

julia> m.captures
3-element Array{Union{Nothing, SubString{String}},1}:
 "a"
 "c"
 "d"

常量

常量通過const關鍵字指定,不過常量還能重定義,REPL只顯示warning並不阻止這樣的做法,只有當重定義不同類型值的時候才會提示Error。文檔強烈不建議重定義常量值。

julia> const a,b = 2,3
(2, 3)

julia> const a,b = 3,2
WARNING: redefining constant a
WARNING: redefining constant b
(3, 2)

julia> a,b
(3, 2)

julia> const a,b = 3.0,2
ERROR: invalid redefinition of constant a

類型

整型和浮點類型值不依賴於平台,有明確的范圍:

Type Signed? Number of bits Smallest value Largest value
Int8 8 -2^7 2^7 - 1
UInt8 8 0 2^8 - 1
Int16 16 -2^15 2^15 - 1
UInt16 16 0 2^16 - 1
Int32 32 -2^31 2^31 - 1
UInt32 32 0 2^32 - 1
Int64 64 -2^63 2^63 - 1
UInt64 64 0 2^64 - 1
Int128 128 -2^127 2^127 - 1
UInt128 128 0 2^128 - 1
Bool N/A 8 false (0) true (1)
Type Precision Number of bits
Float16 half 16
Float32 single 32
Float64 double 64

變量的類型可以通過typeof()獲取,大小可以使用sizeof()獲取,兩者可以參數可以是值也可以是數據類型。

julia> typeof([1,2,4])
Array{Int64,1}

julia> typeof(0xcafebabe)
UInt32

julia> λ =  "special_variable_name"
"special_variable_name"

julia> typeof(λ)
String

julia> typeof(2e-2)
Float64

julia> typeof(Int)
DataType

julia> typeof(String)
DataType

julia> typeof(true)
Bool
julia> sizeof(2e-2)
8

julia> sizeof(Float16)
2

julia> sizeof(Int16(1024))
2

julia> sizeof("hello")
5

julia> sizeof([1,2,3])
24

運算

Julia主要用於數值優化,科學計算等,表達式貼近數學符號。除了日常四則運算外還有平方運算2^10,以及一些新奇的運算符:

julia> √4
2.0

julia> √√16
2.0

julia> typeof(√) #看起來開根號是個sqrt的語法糖
typeof(sqrt)

julia> sqrt(4)
2.0

julia> 2(3+2)
10

julia> x=1
julia> x(x+1)#x放到前面會被解析為可調用對象導致出錯
ERROR: MethodError: objects of type Int64 are not callable
julia> (x+1)x
2

運算符很多,官方文檔已有總結,這里直接復制翻譯一下:

算術運算符 名稱 描述
+x unary plus 恆等運算
-x unary minus 求相反數
x + y binary plus 加法
x - y binary minus 減法
x * y times 乘法
x / y divide 除法
x ÷ y integer divide 整數除法,結果保留整數
x \ y inverse divide 等價於 y / x
x ^ y power 平方
x % y remainder 求余
!x negation !true==false,反之亦然。 只用於bool
位運算符 Name
~x
x & y
x \| y
x ⊻ y 異或(⊻這個符號打出來不容易...)
x >>> y 邏輯 右移
x >> y 算術 右移
x << y 邏輯/算術左移 left
數值比較運算符 Name
== 相等
!=, [](@ref !=) 不相等
< 小於
<=, [](@ref <=) 小於等於
> 大於
>=, [](@ref >=) 大於等於

另外Julia有一個特性,可以進行鏈式比較

julia> 1 < x < 6
true

不用像大多數語言x>1 && x<6那樣手動邏輯組合。

之前介紹說Julia希望有像Matlab一樣強大的線性代數處理表達能力,當然少不了線性代數運算了。可以使用.Operator進行向量運算

julia> [1,2,3].^ 2
3-element Array{Int64,1}:
 1
 4
 9

julia> [1,2,3].+ 2
3-element Array{Int64,1}:
 3
 4
 5

julia> [1,2,3].÷ 2
3-element Array{Int64,1}:
 0
 1
 1

最后Julia還支持分數和復數表示,這里就不贅述了,感興趣的請參見Complex and Rational Numbers

函數和方法

Julia認為函數是一個關聯實參tuple和一個返回值的對象。
第一種形式是完整的函數定義:

function add(a,b)
    x = a+b
    #return x 如果沒有return默認返回最后一個表達式求得的值
end

第二種是賦值形式的函數定義

add2(a,b) = a+b

函數在Julia被視作一等公民,可以賦值給變量,可以做參數,也可以返回。

julia> apply = function(func,arg)
        func(arg)
        end
#269 (generic function with 1 method)

julia> apply(!,false)
true

上面例子中定義了一個匿名函數,即lambda,然后函數!作為參數傳遞。lambda還可以arg -> expr_body進行定義:

julia> lambda = val ->( "$val" * "$val","$val","...")
#317 (generic function with 1 method)

julia> lambda("wow")
("wowwow", "wow", "...")

注意lambda函數體的()表示tuple,它可以讓函數返回多個值。

Julia支持指定參數類型,默認值以及關鍵字形參

julia> misc = function(a::Int,b::Int=2;flag=true)
       a+1,b+2,!flag
       end
#341 (generic function with 2 methods)

julia> misc(1,2,flag=false)
(2, 4, true)

這個小標題是函數和方法,那么方法呢?其實在其他很多語言中,方法是面向對象領域的函數的別稱。這里Julia給了另一種定義:

It is common for the same conceptual function or operation to be implemented quite differently for different types of arguments: adding two integers is very different from adding two floating-point numbers, both of which are distinct from adding an integer to a floating-point number. Despite their implementation differences, these operations all fall under the general concept of "addition". Accordingly, in Julia, these behaviors all belong to a single object: the + function. To facilitate using many different implementations of the same concept smoothly, functions need not be defined all at once, but can rather be defined piecewise by providing specific behaviors for certain combinations of argument types and counts. A definition of one possible behavior for a function is called a method.

方法是函數更具體的表現形式。如果學過C++那完全可以類比,函數就是模板函數,方法就是特化的函數模板。

控制流

Julia的控制流和其他高級語言基本類似,這里就直接給例子了。

  1. 復合表達式
julia> z = begin
    a=1
    b=2
    (a+b,a/b)
end
julia> z
(3, 0.5)
  1. 條件運算
#julia也提供  ?:  三元運算符
if flag && a<b
    println("a <b")
elseif flag && a==b
    println("a==b")
elseif flag && a<b
    println("a>b")
end
  1. while循環
julia> let i=0,res=0
           while i<=100
               res +=i
               i+=1
           end
           println(res)
       end
5050
  1. for循環
julia> for i=1:10
           print(i," ")
       end
1 2 3 4 5 6 7 8 9 10

julia> for name in ["Alice","Andrew","Jane"]
            print(name*" ")
       end
Alice Andrew Jane

julia> while true
       println(i)
       global i+=1
       if i<5
              continue
       else
              break
       end
end
5
  1. 異常處理
julia> throw("exception")
ERROR: "exception"
Stacktrace:
 [1] top-level scope at none:0
 ...


 julia> try
            sqrt(-1)
        catch y
            println(y)
           end
DomainError(-1.0, "sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).")

關於Julia的Task后面我可能會再寫一篇文章詳細說說。

作用域

模塊是現代軟件開發必不可少的成分,Julia也提供了對它的支持。使用module end即可創建一個模塊,import進行導入:

julia> module warehouse
       x = 1
       y = (arg,val) -> arg(arg(val))
       end
WARNING: replacing module warehouse.
Main.warehouse

julia> import .warehouse

julia> warehouse.y(+,2)
2

復合類型

使用struct ... end進行可以創建一個復合類型,這就是Julia提供的面向對象的方法

struct Novel
       name::String
       author::String
       price::Float64

       # 構造函數
       Novel(name::String,author::String,price::Float64) = new(name,author,price)
end

function stringify(val::Novel)
       print("Novel{",val.name,",",val.author,",",val.price,"}")
end
ff = Novel("Gobacktoearth","yy",56.4)
stringify(ff)

Novel{Gobacktoearth,yy,56.4}

我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=wsp9wvpm612x


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM