Julia 函数
函数是一组一起执行一个任务的语句。
在 Julia 里,函数是将参数值组成的元组映射到返回值的一个对象。
Julia 中使用 function 定义函数,基本语法是:
function functionname(args) expression expression expression ... expression end
默认情况下,函数返回的值是最后计算的表达式的值,所以我们看到上面是没有 return 语句的,当然,如果使用 return 关键字,函数就会立即返回:。
julia>function f(x,y) 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
如果函数要返回多个值,可以使用元组:
julia>function mul(x,y) 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
julia>f(a) = a * a 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
返回类型
我们可以使用 :: 运算符来指定函数的返回类型。
julia>function g(x, y)::Int8 return x * y end; julia>typeof(g(1, 2)) Int8
以上函数范例将忽略 x 和 y 的类型,返回 Int8 类型的值。
可选参数
在函数中我们可以设置参数默认值,这样在没有提供该参数的时候,就可以使用默认值来计算:
以下范例定义函数 pos,设置三个参数,其中参数 cz 设置默认值为 0,在函数调用时,可以不提供该参数:
julia>function pos(ax, by, 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
关键字参数
有时候我们定义的一些函数需要大量参数,但调用这些函数可能很麻烦,因为我们可能会忘记提供参数的顺序。 例如:
function foo(a, b, c, d, e, f) ... end
我们可能会忘记参数的顺序,发生以下调用函数的情况:
foo("25", -5.6987, "hello", 56, good, 'ABC') 或 foo("hello", 56, "25", -5.6987, 'ABC', good)
这样看起来就非常混乱。
Julia 关键字参数允许通过名称而不是仅通过位置来识别参数,使得这些复杂函数易于使用和扩展。
使用关键字来标记参数,需要在函数的未标记参数之后使用分号 ;,并在其后跟一个或多个关键值对 key=value,如下所示:
julia> function foo(a, b ; c = 10, d = "hi") 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", "Codebaoku", c=pi, d=22//7) a is Hello b is Codebaoku "c => π, d => 22//7"
使用关键字参数,参数的位置也不太重要了,以上函数我们也可以这样调用:
julia> foo(c=pi, d =22/7, "Hello", "Codebaoku") a is Hello b is Runoob "c => π, d => 3.142857142857143"
1. 匿名函数
匿名函数是一个没有函数名的函数。
匿名函数在程序运行时动态声明,除了没有函数名外,其他的与标准函数一样。
在 Julia 中,匿名函数可用于许多地方,例如 map() 和 列表推导。
使用匿名函数后,我们的代码变得更简洁了。
匿名函数的语法使用符号 ->。
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)
以上范例创建了一个接受一个参数 x 并返回当前值的多项式 x^2+2x-1 的函数。
匿名函数最主要的用法是传递给接收函数作为参数的函数。一个经典的例子是 map ,为数组的每个元素应用一次函数,然后返回一个包含结果值的新数组:
julia> map(round, [1.2, 3.5, 1.7]) 3-element Vector{Float64}: 1.0 4.0 2.0
如果做为第一个参数传递给 map 的转换函数已经存在,那直接使用函数名称是没问题的。但是通常要使用的函数还没有定义好,这样使用匿名函数就更加方便:
julia> map(x -> x^2 + 2x - 1, [1, 3, -1]) 3-element Vector{Int64}: 2 14 -2
接受多个参数的匿名函数写法可以使用语法 (x,y,z)->2x+y-z,而无参匿名函数写作 ()->3 。无参函数的这种写法看起来可能有些奇怪,不过它对于延迟计算很有必要。这种用法会把代码块包进一个无参函数中,后续把它当做 f 调用。
例如,考虑对 get 的调用:
get(dict, key) do # default value calculated here time() end
上面的代码等效于使用包含代码的匿名函数调用 get。 被包围在 do 和 end 之间,如下所示:
get(()->time(), dict, key)
这里对 time 的调用,被包裹了它的一个无参数的匿名函数延迟了。该匿名函数只当 dict 缺少被请求的键时,才被调用。
2. 函数嵌套与递归
在 Julia 中,函数可以嵌套使用。
以下范例 add() 函数内嵌套一个 add1 范例:
julia> function add(x) 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 的计算结果。
julia> sum(x) = x < 1 ? sum(x-1) + x : x 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 项开始,每一项都等于前两项之和。
julia> fib(x) = x < 2 ? x : fib(x-1) + fib(x-2) fib (generic function with 1 method) julia> fib(10) 55 julia> fib(20) 6765
3. Map
Map 定义格式如下:
map(func, coll)
这里,func 是一个函数,它依次应用于集合 coll 的每个元素。 Map 一般包含匿名函数并返回一个新的集合。
julia> map(A -> A^3 + 3A - 3, [10,3,-2]) 3-element Array{Int64,1}: 1027 33 -17
4. Filter
Filter 定义格式如下:
filter(function, collection)
filter 函数返回集合的副本,并删除通过调用该函数结果为 false 的元素。
julia> array = Int[1,2,3] 3-element Array{Int64,1}: 1 2 3 julia> filter(x -> x % 2 == 0, array) 1-element Array{Int64,1}: 2