2.3 函数
[root@itoracle src]# cargo new functions Created binary (application) `functions` package[root@itoracle src]# cd functions/[root@itoracle functions]# vim src/main.rs
Rust code uses snake case as the conventional style for function and variable names. In snake case, all letters are lowercase and underscores separate words. Here’s a program that contains an example function definition:
fn main() { println!("Hello, world!"); another_function();}fn another_function() { println!("Another function.");}
Rust doesn’t care where you define your functions, only that they’re defined somewhere.
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions) Finished dev [unoptimized + debuginfo] target(s) in 6.41s Running `target/debug/functions`Hello, world!Another function.
函数参数
In function signatures, you must declare the type of each parameter. This is a deliberate decision in Rust’s design: requiring type annotations in function definitions means the compiler almost never needs you to use them elsewhere in the code to figure out what you mean.
fn main() { another_function(5, 6);}fn another_function(x: i32, y: i32) { println!("The value of x is: {}", x); println!("The value of y is: {}", y);}
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions) Finished dev [unoptimized + debuginfo] target(s) in 3.03s Running `target/debug/functions`The value of x is: 5The value of y is: 6
函数体
Function bodies are made up of a series of statements optionally ending in an expression.
We’ve actually already used statements and expressions. Statements are instructions that perform some action and do not return a value. Expressions evaluate to a resulting value. Let’s look at some examples.
Creating a variable and assigning a value to it with the let
keyword is a statement. let y = 6;
is a statement.
fn main() { let y = 6;}
Function definitions are also statements; the entire preceding example is a statement in itself.
Statements do not return values. Therefore, you can’t assign a let
statement to another variable, as the following code tries to do; you’ll get an error:
fn main() { let x = (let y = 6);}
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions) error: expected expression, found statement (`let`) --> src/main.rs:2:14 | 2 | let x = (let y = 6); | ^^^ expected expression | = note: variable declaration using `let` is a statement error: aborting due to previous error error: Could not compile `functions`. To learn more, run the command again with --verbose.
The let y = 6
statement does not return a value, so there isn’t anything for x
to bind to.
Expressions evaluate to something and make up most of the rest of the code that you’ll write in Rust. Consider a simple math operation, such as 5 + 6
, which is an expression that evaluates to the value 11
.Expressions can be part of statements: The 6
in the statement let y = 6;
is an expression that evaluates to the value 6
. Calling a function is an expression. Calling a macro is an expression. The block that we use to create new scopes, {}
, is an expression, for example
fn main() { let _x = 5; let _y = { let _x = 3; _x + 1 }; println!("The value of y is: {}", _y); }
let y = { let x = 3; x + 1 };
is a block that, in this case, evaluates to 4
. That value gets bound to y
as part of the let
statement. Note the x + 1
line without a semicolon at the end, which is unlike most of the lines you’ve seen so far. Expressions do not include ending semicolons. If you add a semicolon to the end of an expression, you turn it into a statement, which will then not return a value. Keep this in mind as you explore function return values and expressions next.
[root@itoracle functions]# cargo run src/main.rs Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions) Finished dev [unoptimized + debuginfo] target(s) in 0.63s Running `target/debug/functions src/main.rs`The value of y is: 4
函数返回值
We don’t name return values, but we do declare their type after an arrow (->
). In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function. You can return early from a function by using the return
keyword and specifying a value, but most functions return the last expression implicitly. Here’s an example of a function that returns a value:
fn five() -> i32 { 5}fn main() { let x = five(); println!("The value of x is: {}", x);}
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions) Finished dev [unoptimized + debuginfo] target(s) in 4.96s Running `target/debug/functio
There are two important bits: first, the line let x = five();
shows that we’re using the return value of a function to initialize a variable. Because the function five
returns a 5
, that line is the same as the following:
let x = 5;
Second, the five
function has no parameters and defines the type of the return value, but the body of the function is a lonely 5
with no semicolon because it’s an expression whose value we want to return.
fn main() { let x = plus_one(5); println!("The value of x is: {}", x);}fn plus_one(x: i32) -> i32 { x + 1}
注意,函数体结束的时候没有分号“;”
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions) Finished dev [unoptimized + debuginfo] target(s) in 1.76s Running `target/debug/functions`The value of x is: 6
如果不是在函数体最后一行返回,则可以使用return语句
fn main() { let mut x = plus_one(5); println!("The value of x is: {}", x); x = plus_one(15); println!("The value of x is: {}", x);}fn plus_one(mut x: i32) -> i32 { if x < 10 { return 10; } x = x + 10; x }
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions) Finished dev [unoptimized + debuginfo] target(s) in 1.22s Running `target/debug/functions`The value of x is: 10The value of x is: 25
另外,最后一句使用return语句也是可以的,但rust建议使用不加分号的表达式
fn main() { let mut x = plus_one(5); println!("The value of x is: {}", x); x = plus_one(15); println!("The value of x is: {}", x);}fn plus_one(mut x: i32) -> i32 { if x < 10 { return 10; } x = x + 10; return x; }
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions) Finished dev [unoptimized + debuginfo] target(s) in 2.43s Running `target/debug/functions`The value of x is: 10The value of x is: 25
没有返回值的函数
fn justgo(){ println!("永远是多远?");}
[root@itoracle functions]# cat src/main.rs fn main() { let mut x = plus_one(5); println!("The value of x is: {}", x); x = plus_one(15); println!("The value of x is: {}", x); justgo();}fn plus_one(mut x: i32) -> i32 { if x < 10 { return 10; } x = x + 10; x}fn justgo(){ println!("永远是多远?");}
运行结果
[root@itoracle functions]# cargo run Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions) Finished dev [unoptimized + debuginfo] target(s) in 4.95s Running `target/debug/functions`The value of x is: 10The value of x is: 25永远是多远?
函数定义后,必须被调用,不然运行时会给出警告
warning: function is never used: `justgo` --> src/main.rs:19:1 | 19 | fn justgo(){ | ^^^^^^^^^^^ Finished dev [unoptimized + debuginfo] target(s) in 5.48s Running `target/debug/functions`