Julia 函数
函数是一组一起执行一个任务的语句。
在 Julia 里,函数是将参数值组成的元组映射到返回值的一个对象。
Julia 中使用 function 定义函数,基本语法是:
function functionname(args) expression expression expression ... expression end
默认情况下,函数返回的值是最后计算的表达式的值,所以我们看到上面是没有 return 语句的,当然,如果使用 return 关键字,函数就会立即返回:。
实例代码
x + y
end
f (generic function with 1 method)
julia> f(2,3)
5
julia> function bills(money)
if money < 0
return false
else
return true
end
end
bills (generic function with 1 method)
julia> bills(50)
true
julia> bills(-50)
false
如果函数要返回多个值,可以使用元组:
实例代码
x+y, x*y
end
mul (generic function with 1 method)
julia> mul(5, 10)
(15, 50)
当函数中只有一个表达式时,您可以省略 function 关键字,等号左侧设置函数名与参数,右侧设置表达式,类似赋值形式:
julia> f(x,y) = x + y f (generic function with 1 method)
没有括号时,表达式 f 指的是函数对象,可以像任何值一样被传递:
julia> g = f; julia> g(2,3) 5
实例代码
f (generic function with 1 method)
julia> f(5)
25
julia> func(x, y) = sqrt(x^2 + y^2)
func (generic function with 1 method)
julia> func(5, 4)
6.4031242374328485
和变量名一样,Unicode 字符也可以用作函数名:
julia> ∑(x,y) = x + y ∑ (generic function with 1 method) julia> ∑(2, 3) 5
返回类型
我们可以使用 :: 运算符来指定函数的返回类型。
实例代码
return x * y
end;
julia> typeof(g(1, 2))
Int8
以上函数实例将忽略 x 和 y 的类型,返回 Int8 类型的值。
可选参数
在函数中我们可以设置参数默认值,这样在没有提供该参数的时候,就可以使用默认值来计算:
以下实例定义函数 pos,设置三个参数,其中参数 cz 设置默认值为 0,在函数调用时,可以不提供该参数:
实例代码
println("$ax, $by, $cz")
end
pos (generic function with 2 methods)
julia> pos(10, 30)
10, 30, 0
julia> pos(10, 30, 50)
10, 30, 50
关键字参数
有时候我们定义的一些函数需要大量参数,但调用这些函数可能很麻烦,因为我们可能会忘记提供参数的顺序。 例如:
...
end
我们可能会忘记参数的顺序,发生以下调用函数的情况:
foo("25", -5.6987, "hello", 56, good, 'ABC') 或 foo("hello", 56, "25", -5.6987, 'ABC', good)
这样看起来就非常混乱。
Julia 关键字参数允许通过名称而不是仅通过位置来识别参数,使得这些复杂函数易于使用和扩展。
使用关键字来标记参数,需要在函数的未标记参数之后使用分号 ;,并在其后跟一个或多个关键值对 key=value,如下所示:
实例代码
println("a is $a")
println("b is $b")
return "c => $c, d => $d"
end
foo (generic function with 1 method)
julia> foo(100,20)
a is 100
b is 20
"c => 10, d => hi"
julia> foo("Hello", "Haodaima", c=pi, d=22//7)
a is Hello
b is Haodaima
"c => π, d => 22//7"
使用关键字参数,参数的位置也不太重要了,以上函数我们也可以这样调用:
实例代码
a is Hello
b is Haodaima
"c => π, d => 3.142857142857143"
匿名函数
匿名函数是一个没有函数名的函数。
匿名函数在程序运行时动态声明,除了没有函数名外,其他的与标准函数一样。
在 Julia 中,匿名函数可用于许多地方,例如 map() 和 列表推导。
使用匿名函数后,我们的代码变得更简洁了。
匿名函数的语法使用符号 ->。
实例代码
#1 (generic function with 1 method)
julia> function (x)
x^2 + 2x - 1
end
#3 (generic function with 1 method)
以上实例创建了一个接受一个参数 x 并返回当前值的多项式 x^2+2x-1 的函数。
匿名函数最主要的用法是传递给接收函数作为参数的函数。一个经典的例子是 map ,为数组的每个元素应用一次函数,然后返回一个包含结果值的新数组:
实例代码
3-element Vector{Float64}:
1.0
4.0
2.0
如果做为第一个参数传递给 map 的转换函数已经存在,那直接使用函数名称是没问题的。但是通常要使用的函数还没有定义好,这样使用匿名函数就更加方便:
实例代码
3-element Vector{Int64}:
2
14
-2
接受多个参数的匿名函数写法可以使用语法 (x,y,z)->2x+y-z,而无参匿名函数写作 ()->3 。无参函数的这种写法看起来可能有些奇怪,不过它对于延迟计算很有必要。这种用法会把代码块包进一个无参函数中,后续把它当做 f 调用。
例如,考虑对 get 的调用:
实例代码
# default value calculated here
time()
end
上面的代码等效于使用包含代码的匿名函数调用 get。 被包围在 do 和 end 之间,如下所示:
get(()->time(), dict, key)
这里对 time 的调用,被包裹了它的一个无参数的匿名函数延迟了。该匿名函数只当 dict 缺少被请求的键时,才被调用。
函数嵌套与递归
在 Julia 中,函数可以嵌套使用。
以下实例 add() 函数内嵌套一个 add1 实例:
实例代码
Y = x * 2
function add1(Y)
Y += 1
end
add1(Y)
end
add (generic function with 1 method)
julia> d = 10
10
julia> add(d)
21
同样,Julia 中的函数也可以是递归的。
递归指的是在函数的定义中使用函数自身的方法。
举个例子:
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?"从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?'从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……'"
以下我们使用三元运算符来测试递归,三元运算符操作三个操作对象 expr ? a : b,如果 expr 为 true ,值为 a 的计算结果 ,否则为 b 的计算结果。
实例代码
sum (generic function with 1 method)
julia> sum(10)
55
以上实例用于计算某个整数之前所有数的总和,直到并包括某个数字。 在这个递归中,因为有一个基本情况,即当 x 为 1 时,这个值被返回。
递归最著名的例子是计算第 n 个斐波那契数,斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........
这个数列从第 3 项开始,每一项都等于前两项之和。
实例代码
fib (generic function with 1 method)
julia> fib(10)
55
julia> fib(20)
6765
Map
Map 定义格式如下:
map(func, coll)
这里,func 是一个函数,它依次应用于集合 coll 的每个元素。 Map 一般包含匿名函数并返回一个新的集合。
实例代码
3-element Array{Int64,1}:
1027
33
-17
Filter
Filter 定义格式如下:
filter(function, collection)
filter 函数返回集合的副本,并删除通过调用该函数结果为 false 的元素。
实例代码
3-element Array{Int64,1}:
1
2
3
julia> filter(x -> x % 2 == 0, array)
1-element Array{Int64,1}:
2