# Introducing Julia/Controlling the flow

 « Introducing JuliaControlling the flow » Types Functions

### 控制流程的不同方法

• 三元 复合表达式
• 布尔转换表达式
• if elseif else end - 条件求值
• for end - 迭代求值
• while end - 迭代条件求值
• try catch error throw 异常处理
• do 代码块

### 三元表达式

```julia> x = 1
1
julia> x > 3 ? "yes" : "no"
"no"
julia> x = 5
5
julia> x > 3 ? "yes" : "no"
"yes"
```

```julia> x = 0.3
0.3
julia> x < 0.5 ? sin(x) : cos(x)
0.29552020666133955
```

Julia 返回 `sin(x)` 的值， 因为 x 小于 0.5. `cos(x)` 根本没有被计算求值。

### 布尔转换表达式

```julia> isodd(1000003) && @warn("That's odd!")
WARNING: That's odd!

julia> isodd(1000004) && @warn("That's odd!")
false
```

```julia> isodd(1000003) || @warn("That's odd!")
true

julia> isodd(1000004) || @warn("That's odd!")
WARNING: That's odd!
```

### If and Else

```name = "Julia"
if name == "Julia"
println("I like Julia")
elseif name == "Python"
println("I like Python.")
println("But I prefer Julia.")
else
println("I don't know what I like")
end
```

`elseif``else` 的这部分是可选的：

```name = "Julia"
if name == "Julia"
println("I like Julia")
end
```

"switch"和"case"语句呢？emmmm，你不需要学习这些语法，因为他们不存在！

#### ifelse

```julia> s = ifelse(false, "hello", "goodbye") * " world"
```

`ifelse` 是一个普通函数，它计算所有参数，并根据第一个参数的值返回第二个或第三个参数。使用条件 `if``? ... :`，只对所选路由中的表达式求值。或者，也可以这样:

```julia> x = 10
10
```
```julia> if x > 0
"positive"
else
"negative or zero"
end
"positive"
```
```julia> r = if x > 0
"positive"
else
"negative or zero"
end
"positive"

julia> r
"positive"
```

### for循环 和 迭代

```julia> for i in 0:10:100
println(i)
end
0
10
20
30
40
50
60
70
80
90
100
```

```julia> for color in ["red", "green", "blue"] # an array
print(color, " ")
end
red green blue
```
```julia> for letter in "julia" # a string
print(letter, " ")
end
j u l i a
```
```julia> for element in (1, 2, 4, 8, 16, 32) # a tuple
print(element, " ")
end
1 2 4 8 16 32
```
```julia> for i in Dict("A"=>1, "B"=>2) # a dictionary
println(i)
end
"B"=>2
"A"=>1
```
```julia> for i in Set(["a", "e", "a", "e", "i", "o", "i", "o", "u"])
println(i)
end
e
o
u
a
i
```

```julia> a = reshape(1:100, (10, 10))
10x10 Array{Int64,2}:
1  11  21  31  41  51  61  71  81   91
2  12  22  32  42  52  62  72  82   92
3  13  23  33  43  53  63  73  83   93
4  14  24  34  44  54  64  74  84   94
5  15  25  35  45  55  65  75  85   95
6  16  26  36  46  56  66  76  86   96
7  17  27  37  47  57  67  77  87   97
8  18  28  38  48  58  68  78  88   98
9  19  29  39  49  59  69  79  89   99
10  20  30  40  50  60  70  80  90  100
```
```julia> for n in a
print(n, " ")
end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
```

##### 迭代数组并更新

```julia> c = [1]
1-element Array{Int64,1}:
1

julia> for i in c
push!(c, i)
@show c
sleep(1)
end

c = [1,1]
c = [1,1,1]
c = [1,1,1,1]
...
```

#### 循环变量和作用域

```julia> for i in 1:10
@show i
end
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10

julia> i
ERROR: UndefVarError: i not defined
```

```julia> for i in 1:10
global howfar
if i % 4 == 0
howfar = i
end
end
```
```julia> howfar
8
```

```function f()
howfar = 0
for i in 1:10
if i % 4 == 0
howfar = i
end
end
return howfar
end

@show f()
```
`8`

#### 循环中声明的变量

```julia> for i in 1:5
k = i^2
println("\$(i) squared is \$(k)")
end
```
```1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
```

```julia> k
ERROR: UndefVarError: k not defined
```

```for i in 1:10
z = i
println("z is \$z")
end
```
```z is 1
z is 2
z is 3
z is 4
z is 5
z is 6
z is 7
z is 8
z is 9
z is 10```

```julia> counter = 0
0

julia> for i in 1:10
global counter
counter += i
end

julia> counter
55
```

```for i in 1:10
if ! @isdefined z
println("z isn't defined")
end
z = i
println("z is \$z")
end
```

```z isn't defined
z is 1
z isn't defined
z is 2
z isn't defined
z is 3
z isn't defined
z is 4
z isn't defined
z is 5
z isn't defined
z is 6
z isn't defined
z is 7
z isn't defined
z is 8
z isn't defined
z is 9
z isn't defined
z is 10
```

```for i in 1:10
global z
if ! @isdefined z
println("z isn't defined")
else
println("z was \$z")
end
z = i
println("z is \$z")
end
```
```z isn't defined
z is 1
z was 1
z is 2
z was 2
...
z is 9
z was 9
z is 10```

although, if you're working in global scope, `z` is now available everywhere, with the value 10.

```function f()
counter = 0
for i in 1:10
counter += i
end
return counter
end
```
```julia> f()
55
```

#### 循环微调：continue

```for i in 1:10
if i % 3 == 0
continue
end
println(i) # this and subsequent lines are
# skipped if i is a multiple of 3
end

1
2
4
5
7
8
10
```

#### 推导

```"设S是所有元素n的集合，其中n大于或等于1，小于或等于10。"
```

```julia> S = Set([n for n in 1:10])
Set([7,4,9,10,2,3,5,8,6,1])
```

`[n for n in 1:10]` 的结构被称为 数组推导列表推导 ("comprehension"，意思是“得到一切”，而不是“理解”)。外面的方括号将通过 计算放置在 for 迭代之前的表达式 而生成的元素集合在一起。而不是`end` ，使用方括号完成。

```julia> [i^2 for i in 1:10]
10-element Array{Int64,1}:
1
4
9
16
25
36
49
64
81
100
```

```julia> Complex[i^2 for i in 1:10]
10-element Array{Complex,1}:
1.0+0.0im
4.0+0.0im
9.0+0.0im
16.0+0.0im
25.0+0.0im
36.0+0.0im
49.0+0.0im
64.0+0.0im
81.0+0.0im
100.0+0.0im
```

```julia> [(i, sqrt(i)) for i in 1:10]
10-element Array{Tuple{Int64,Float64},1}:
(1,1.0)
(2,1.41421)
(3,1.73205)
(4,2.0)
(5,2.23607)
(6,2.44949)
(7,2.64575)
(8,2.82843)
(9,3.0)
(10,3.16228)
```

```julia> Dict(string(Char(i + 64)) => i for i in 1:26)
Dict{String,Int64} with 26 entries:
"Z" => 26
"Q" => 17
"W" => 23
"T" => 20
"C" => 3
"P" => 16
"V" => 22
"L" => 12
"O" => 15
"B" => 2
"M" => 13
"N" => 14
"H" => 8
"A" => 1
"X" => 24
"D" => 4
"G" => 7
"E" => 5
"Y" => 25
"I" => 9
"J" => 10
"S" => 19
"U" => 21
"K" => 11
"R" => 18
"F" => 6
```

```julia> [(r,c) for r in 1:5, c in 1:2]
5×2 Array{Tuple{Int64,Int64},2}:
(1,1)  (1,2)
(2,1)  (2,2)
(3,1)  (3,2)
(4,1)  (4,2)
(5,1)  (5,2)
```

`r` 经过五个循环，每个 `c` 的值对应一个循环。 嵌套循环 的工作方式正好相反。此处将遵守列主次顺序，如阵列中填充了纳秒时间值时所示：

```julia> [Int(time_ns()) for r in 1:5, c in 1:2]
5×2 Array{Int64,2}:
1223184391741562  1223184391742642
1223184391741885  1223184391742817
1223184391742067  1223184391743009
1223184391742256  1223184391743184
1223184391742443  1223184391743372
```

```julia> [x for x in 1:100 if x % 7 == 0]
14-element Array{Int64,1}:
7
14
21
28
35
42
49
56
63
70
77
84
91
98
```
##### 生成表达式

```julia> sum(x^2 for x in 1:10)
385
```
```julia> collect(x for x in 1:100 if x % 7 == 0)
14-element Array{Int64,1}:
7
14
21
28
35
42
49
56
63
70
77
84
91
98
```

#### 枚举数组

```julia> m = rand(0:9, 3, 3)
3×3 Array{Int64,2}:
6  5  3
4  0  7
1  7  4

julia> [i for i in enumerate(m)]
3×3 Array{Tuple{Int64,Int64},2}:
(1, 6)  (4, 5)  (7, 3)
(2, 4)  (5, 0)  (8, 7)
(3, 1)  (6, 7)  (9, 4)
```

#### 数组压缩

```julia> for i in zip(0:10, 100:110, 200:210)
println(i)
end
```
```(0,100,200)
(1,101,201)
(2,102,202)
(3,103,203)
(4,104,204)
(5,105,205)
(6,106,206)
(7,107,207)
(8,108,208)
(9,109,209)
(10,110,210)
```

```julia> for i in zip(0:10, 100:110, 200:215)
println(i)
end
(0,100,200)
(1,101,201)
(2,102,202)
(3,103,203)
(4,104,204)
(5,105,205)
(6,106,206)
(7,107,207)
(8,108,208)
(9,109,209)
(10,110,210)
```

```julia> for i in zip(0:15, 100:110, 200:210)
println(i)
end
(0,100,200)
(1,101,201)
(2,102,202)
(3,103,203)
(4,104,204)
(5,105,205)
(6,106,206)
(7,107,207)
(8,108,208)
(9,109,209)
(10,110,210)
```

```(v1.0) julia> [i for i in zip(0:4, 100:102, 200:202)]
ERROR: DimensionMismatch("dimensions must match")
Stacktrace:
[1] promote_shape at ./indices.jl:129 [inlined]
[2] axes(::Base.Iterators.Zip{UnitRange{Int64},Base.Iterators.Zip2{UnitRange{Int64},UnitRange{Int64}}}) at ./iterators.jl:371
[3] _array_for at ./array.jl:611 [inlined]
[4] collect(::Base.Generator{Base.Iterators.Zip{UnitRange{Int64},Base.Iterators.Zip2{UnitRange{Int64},UnitRange{Int64}}},getfield(Main, Symbol("##5#6"))}) at ./array.jl:624
[5] top-level scope at none:0
```
```(v1.0) julia> [i for i in zip(0:2, 100:102, 200:202)]
3-element Array{Tuple{Int64,Int64,Int64},1}:
(0, 100, 200)
(1, 101, 201)
(2, 102, 202)
```

#### 可迭代对象

```julia> ro = 0:2:100
0:2:100
```

```julia> [i for i in ro]
51-element Array{Int64,1}:
0
2
4
6
8
10
12
14
16
18
20
22
24
26
28
⋮
74
76
78
80
82
84
86
88
90
92
94
96
98
100
```

```julia> collect(0:25:100)
5-element Array{Int64,1}:
0
25
50
75
100
```

```julia> collect(permutations(1:4))
24-element Array{Array{Int64,1},1}:
[1,2,3,4]
[1,2,4,3]
…
[4,3,2,1]
```

Julia为处理其他类型的数据提供了可迭代的对象。例如，在处理文件时，可以将打开的文件视为可迭代对象：

``` filehandle = "/Users/me/.julia/logs/repl_history.jl"
for line in eachline(filehandle)
println(length(line), line)
end
```
##### 使用 eachindex()

``` for i = 1:length(A)
# do something with i or A[i]
end
```

``` for i in eachindex(A)
# do something with i or A[i]
end
```

#### 更多迭代器

```(v1.0) pkg> ] add IterTools
julia> using IterTools
```

```julia> collect(partition(1:10, 3, 1))
8-element Array{Tuple{Int64,Int64,Int64},1}:
(1, 2, 3)
(2, 3, 4)
(3, 4, 5)
(4, 5, 6)
(5, 6, 7)
(6, 7, 8)
(7, 8, 9)
(8, 9, 10)
```

`chain()` 一个接一个地处理所有迭代器：

``` for i in chain(1:3, ['a', 'b', 'c'])
@show i
end

i = 1
i = 2
i = 3
i = 'a'
i = 'b'
i = 'c'
```

`subsets()` 处理对象的所有子集。可以指定大小：

``` for i in subsets(collect(1:6), 3)
@show i
end

i = [1,2,3]
i = [1,2,4]
i = [1,2,5]
i = [1,2,6]
i = [1,3,4]
i = [1,3,5]
i = [1,3,6]
i = [1,4,5]
i = [1,4,6]
i = [1,5,6]
i = [2,3,4]
i = [2,3,5]
i = [2,3,6]
i = [2,4,5]
i = [2,4,6]
i = [2,5,6]
i = [3,4,5]
i = [3,4,6]
i = [3,5,6]
i = [4,5,6]
```

#### 嵌套循环

```julia> for x in 1:10, y in 1:10
@show (x, y)
end
(x,y) = (1,1)
(x,y) = (1,2)
(x,y) = (1,3)
(x,y) = (1,4)
(x,y) = (1,5)
(x,y) = (1,6)
(x,y) = (1,7)
(x,y) = (1,8)
(x,y) = (1,9)
(x,y) = (1,10)
(x,y) = (2,1)
(x,y) = (2,2)
(x,y) = (2,3)
(x,y) = (2,4)
(x,y) = (2,5)
(x,y) = (2,6)
(x,y) = (2,7)
(x,y) = (2,8)
(x,y) = (2,9)
(x,y) = (2,10)
(x,y) = (3,1)
(x,y) = (3,2)
...
(x,y) = (9,9)
(x,y) = (9,10)
(x,y) = (10,1)
(x,y) = (10,2)
(x,y) = (10,3)
(x,y) = (10,4)
(x,y) = (10,5)
(x,y) = (10,6)
(x,y) = (10,7)
(x,y) = (10,8)
(x,y) = (10,9)
(x,y) = (10,10)
```

(十分有用的`@show` 宏打印出东西的名称及其值。)

```julia> for x in 1:10
for y in 1:10
@show (x, y)
if y % 3 == 0
break
end
end
end
(x,y) = (1,1)
(x,y) = (1,2)
(x,y) = (1,3)
(x,y) = (2,1)
(x,y) = (2,2)
(x,y) = (2,3)
(x,y) = (3,1)
(x,y) = (3,2)
(x,y) = (3,3)
(x,y) = (4,1)
(x,y) = (4,2)
(x,y) = (4,3)
(x,y) = (5,1)
(x,y) = (5,2)
(x,y) = (5,3)
(x,y) = (6,1)
(x,y) = (6,2)
(x,y) = (6,3)
(x,y) = (7,1)
(x,y) = (7,2)
(x,y) = (7,3)
(x,y) = (8,1)
(x,y) = (8,2)
(x,y) = (8,3)
(x,y) = (9,1)
(x,y) = (9,2)
(x,y) = (9,3)
(x,y) = (10,1)
(x,y) = (10,2)
(x,y) = (10,3)

julia> for x in 1:10, y in 1:10
@show (x, y)
if y % 3 == 0
break
end
end
(x,y) = (1,1)
(x,y) = (1,2)
(x,y) = (1,3)
```

#### 优化嵌套循环

```+-----+-----+-----+--+
|  1  |  5  |  9  |
|     |     |     |
+--------------------+
|  2  |  6  |  10 |
|     |     |     |
+--------------------+
|  3  |  7  |  11 |
|     |     |     |
+--------------------+
|  4  |  8  |  12 |
|     |     |     |
+-----+-----+-----+--+
```

```function laplacian_bad(lap_x::Array{Float64,2}, x::Array{Float64,2})
nr, nc = size(x)
for ir = 2:nr-1, ic = 2:nc-1 # bad loop nesting order
lap_x[ir, ic] =
(x[ir+1, ic] + x[ir-1, ic] +
x[ir, ic+1] + x[ir, ic-1]) - 4*x[ir, ic]
end
end
```

```function laplacian_good(lap_x::Array{Float64,2}, x::Array{Float64,2})
nr,nc = size(x)
for ic = 2:nc-1, ir = 2:nr-1 # good loop nesting order
lap_x[ir,ic] =
(x[ir+1,ic] + x[ir-1,ic] +
x[ir,ic+1] + x[ir,ic-1]) - 4*x[ir,ic]
end
end
```

```function laplacian_good_nocheck(lap_x::Array{Float64,2}, x::Array{Float64,2})
nr,nc = size(x)
for ic = 2:nc-1, ir = 2:nr-1 # good loop nesting order
@inbounds begin lap_x[ir,ic] = # no array bounds checking
(x[ir+1,ic] +  x[ir-1,ic] +
x[ir,ic+1] + x[ir,ic-1]) - 4*x[ir,ic]
end
end
end
```

```function main_test(nr, nc)
field = zeros(nr, nc)
for ic = 1:nc, ir = 1:nr
if ir == 1 || ic == 1 || ir == nr || ic == nc
field[ir,ic] = 1.0
end
end
lap_field = zeros(size(field))

t = @elapsed laplacian_good(lap_field, field)

t = @elapsed laplacian_good_nocheck(lap_field, field)
end
```

```julia> main_test(10000,10000)
laplacian_good                0.190697149
laplacian_good no check       0.092164871
```

### 创建自用的可迭代对象

```mutable struct SN
str::String
num::Int64
end
```

```sn = SN("A", 1)
```

```function Base.iterate(sn::SN)
str = sn.str
num = sn.num

if num == 9
nextnum = 1
nextstr = string(Char(Int(str[1])) + 1)
else
nextnum = num + 1
nextstr = str
end

return (sn, SN(nextstr, nextnum))
end
```

`iterate()`的第二个方法接受两个参数：可迭代对象和当前状态。它再次返回包含两个值的元组，即下一项和下一状态。但是首先，如果没有更多的值可用，`iterate()`函数应该什么也不会返回。

```function Base.iterate(sn::SN, state)

# check if we've finished?
if state.str == "[" # when Z changes to [ we're done
return
end

# we haven't finished, so we'll use the incoming one immediately
str = state.str
num = state.num

# and prepare the one after that, to be saved for later
if num == 9
nextnum = 1
nextstr = string(Char(Int(str[1])) + 1)
else
nextnum = num + 1
nextstr = state.str
end

# return: the one to use next, the one after that
return (SN(str, num), SN(nextstr, nextnum))
end
```

```Base.show(io::IO, sn::SN) = print(io, string(sn.str, sn.num))

function Base.length(sn::SN)
cn1 = Char(Int(Char(sn.str[1]) + 1))
cnz = Char(Int(Char('Z')))
(length(cn1:cnz) * 9) + (10 - sn.num)
end
```

```julia> sn = SN("A", 1)
A1

julia> for i in sn
@show i
end
```
```i = A1
i = A2
i = A3
i = A4
i = A5
i = A6
i = A7
i = A8
...
i = Z6
i = Z7
i = Z8
i = Z9
```
```julia> for sn in SN("K", 9)
print(sn, " ")
end
```
```K9 L1 L2 L3 L4 L5 L6 L7 L8 L9 M1 M2 M3 M4 M5 M6 M7 M8 M9 N1 N2 N3 N4 N5 N6 N7 N8
N9 O1 O2 O3 O4 O5 O6 O7 O8 O9 P1 P2 P3 P4 P5 P6 P7 P8 P9 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8
Q9 R1 R2 R3 R4 R5 R6 R7 R8 R9 S1 S2 S3 S4 S5 S6 S7 S8 S9 T1 T2 T3 T4 T5 T6 T7 T8
T9 U1 U2 U3 U4 U5 U6 U7 U8 U9 V1 V2 V3 V4 V5 V6 V7 V8 V9 W1 W2 W3 W4 W5 W6 W7 W8
W9 X1 X2 X3 X4 X5 X6 X7 X8 X9 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Z1 Z2 Z3 Z4 Z5 Z6 Z7 Z8
Z9```
```julia> collect(SN("Q", 7)),
(Any[Q7, Q8, Q9, R1, R2, R3, R4, R5, R6, R7  …  Y9, Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9],)
```

### While 循环

```julia> x = 0
0
julia> while x < 4
println(x)
global x += 1
end

0
1
2
3
```

```while true
println(x)
x += 1
x >= 4 && break
end

0
1
2
3
```

### 异常

```julia> s = "string";
julia> try
s[1] = "p"
catch e
println("caught an error: \$e")
println("but we can continue with execution...")
end

caught an error: MethodError(setindex!,("string","p",1)) but we can continue with execution...
```

`error()`函数使用给定的消息引发错误异常。

### Do block

```julia> smallprimes = [1,2,3,5,7,11,13,17,19,23];
```
```julia> findall(x -> isequal(13, x), smallprimes)
1-element Array{Int64,1}:
7
```

anonymous function 匿名函数 (`x -> isequal(13, x)``find()`的第一个参数，它对第二个参数进行操作。但是有了`do`代码块，你就可以把函数拿出来放在`do`之间……

```julia> findall(smallprimes) do x
isequal(x, 13)
end
1-element Array{Int64,1}:
7
```

 « Introducing JuliaControlling the flow » Types Functions