# 函数

``````julia> function f(x,y)
x + y
end
f (generic function with 1 method)``````

``````julia> f(x,y) = x + y
f (generic function with 1 method)``````

``````julia> x -> x^2 + 2x - 1
#1 (generic function with 1 method)

julia> function (x)
x^2 + 2x - 1
end
#3 (generic function with 1 method)``````

``````julia> map(round, [1.2,3.5,1.7])
3-element Array{Float64,1}:
1.0
4.0
2.0``````

``````julia> map(x -> x^2 + 2x - 1, [1,3,-1])
3-element Array{Int64,1}:
2
14
-2``````

## 元组

Julia 有一个和函数参数与返回值密切相关的内置数据结构叫做元组（tuple）。

``````julia> (1, 1+1)
(1, 2)

julia> (1,)
(1,)

julia> x = (0.0, "hello", 6*7)
(0.0, "hello", 42)

julia> x[2]
"hello"``````

## 具名元组

``````julia> x = (a=1, b=1+1)
(a = 1, b = 2)

julia> x.a
1``````

## 多返回值

Julia 中，一个函数可以返回一个元组来实现返回多个值。不过，元组的创建和消除都不一定要用括号，这时候给人的感觉就是返回了多个值而非一个元组。比如下面这个例子，函数返回了两个值：

``````julia> function foo(a,b)
a+b, a*b
end
foo (generic function with 1 method)``````

``````julia> foo(2,3)
(5, 6)``````

``````julia> x, y = foo(2,3)
(5, 6)

julia> x
5

julia> y
6``````

``````function foo(a,b)
return a+b, a*b
end``````

## 参数解构

``````julia> minmax(x, y) = (y < x) ? (y, x) : (x, y)

julia> range((min, max)) = max - min

julia> range(minmax(10, 2))
8``````

## 变参函数

``````julia> bar(a,b,x...) = (a,b,x)
bar (generic function with 1 method)``````

``````julia> bar(1,2)
(1, 2, ())

julia> bar(1,2,3)
(1, 2, (3,))

julia> bar(1, 2, 3, 4)
(1, 2, (3, 4))

julia> bar(1,2,3,4,5,6)
(1, 2, (3, 4, 5, 6))``````

``````julia> x = (3, 4)
(3, 4)

julia> bar(1,2,x...)
(1, 2, (3, 4))``````

``````julia> x = (2, 3, 4)
(2, 3, 4)

julia> bar(1,x...)
(1, 2, (3, 4))

julia> x = (1, 2, 3, 4)
(1, 2, 3, 4)

julia> bar(x...)
(1, 2, (3, 4))``````

``````julia> x = [3,4]
2-element Array{Int64,1}:
3
4

julia> bar(1,2,x...)
(1, 2, (3, 4))

julia> x = [1,2,3,4]
4-element Array{Int64,1}:
1
2
3
4

julia> bar(x...)
(1, 2, (3, 4))``````

``````julia> baz(a,b) = a + b;

julia> args = [1,2]
2-element Array{Int64,1}:
1
2

julia> baz(args...)
3

julia> args = [1,2,3]
3-element Array{Int64,1}:
1
2
3

julia> baz(args...)
ERROR: MethodError: no method matching baz(::Int64, ::Int64, ::Int64)
Closest candidates are:
baz(::Any, ::Any) at none:1``````

## 可选参数

``````function Date(y::Int64, m::Int64=1, d::Int64=1)
err = validargs(Date, y, m, d)
err === nothing || throw(err)
return Date(UTD(totaldays(y, m, d)))
end``````

``````julia> using Dates

julia> Date(2000, 12, 12)
2000-12-12

julia> Date(2000, 12)
2000-12-01

julia> Date(2000)
2000-01-01``````

## 关键字参数

``````function plot(x, y; style="solid", width=1, color="black")
###
end``````

``````function f(;x::Int=1)
###
end``````

``````function f(x; y=0, kwargs...)
###
end``````

`f` 内部，`kwargs` 会是一个具名元组。具名元组（以及键类型为 `Symbol` 的字典）可作为关键字参数传递，这通过在调用中使用分号，例如 `f(x, z=1; kwargs...)`

``````function f(x; y)
###
end
f(3, y=5) # ok, y is assigned
f(3)      # throws UndefKeywordError(:y)``````

## 默认值作用域的计算

``````function f(x, a=b, b=1)
###
end``````

`a=b` 中的 `b` 指的是外部作用域内的 `b`，而不是后续参数中的 `b`

## 函数参数中的 Do 结构

``````map(x->begin
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end,
[A, B, C])``````

Julia 提供了一个保留字 `do`，用于更清楚地重写此代码：

``````map([A, B, C]) do x
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end``````

`do x` 语法创建一个带有参数 `x` 的匿名函数，并将其作为第一个参数传递 `map`。类似地，`do a，b` 会创建一个双参数匿名函数，而一个简单的 `do` 会声明一个满足形式 `() -> ...` 的匿名函数。

``````open("outfile", "w") do io
write(io, data)
end``````

``````function open(f::Function, args...)
io = open(args...)
try
f(io)
finally
close(io)
end
end``````

``````julia> A = [1.0, 2.0, 3.0]
3-element Array{Float64,1}:
1.0
2.0
3.0

julia> sin.(A)
3-element Array{Float64,1}:
0.8414709848078965
0.9092974268256817
0.1411200080598672``````

``````julia> f(x,y) = 3x + 4y;

julia> A = [1.0, 2.0, 3.0];

julia> B = [4.0, 5.0, 6.0];

julia> f.(pi, A)
3-element Array{Float64,1}:
13.42477796076938
17.42477796076938
21.42477796076938

julia> f.(A, B)
3-element Array{Float64,1}:
19.0
26.0
33.0``````

``````julia> Y = [1.0, 2.0, 3.0, 4.0];

julia> X = similar(Y); # pre-allocate output array

julia> @. X = sin(cos(Y)) # equivalent to X .= sin.(cos.(Y))
4-element Array{Float64,1}:
0.5143952585235492
-0.4042391538522658
-0.8360218615377305
-0.6080830096407656``````

`.+` 这样的二元（或一元）运算符使用相同的机制进行管理：它们等价于 `broadcast` 调用且可与其它嵌套的「点」调用融合。`X .+= Y` 等等价于 `X .= X .+ Y`，结果为一个融合的 in-place 赋值；另见 [dot operators](http://127.0.0.5/@ref man-dot-operators)。

``````julia> [1:5;] .|> [x->x^2, inv, x->2*x, -, isodd]
5-element Array{Real,1}:
1
0.5
6
-4
true``````