RustPrimer
  • Introduction
  • 初识Rust
  • 安装Rust
    • Linux
    • Mac
    • Windows
    • 版本管理工具: rustup
  • 编辑器
    • 前期准备
    • vim
    • emacs
    • vscode
    • atom
    • sublime
    • visual studio
    • spacemacs
  • Rust快速入门
    • Rust旅程
    • 变量绑定与原生类型
    • 数组、动态数组和字符串
    • 结构体与枚举
    • 控制流
    • 函数与方法
    • 特性
    • 注释与文档
    • 输入输出流
  • Cargo项目管理器
  • 基本程序结构
    • 注释
    • 条件
    • 循环
  • 类型、运算符和字符串
    • 基础类型
    • 复合类型
    • 字符串类
    • 基础运算符和字符串格式化
  • 函数
    • 函数参数
    • 函数返回值
    • 语句和表达式
    • 高阶函数
  • 模式匹配
    • match关键字
    • 模式 pattern
  • 特征 Trait
    • trait关键字
    • trait对象
  • 泛型
  • 可变性、所有权、租借和生命期
    • 所有权
    • 引用和借用
    • 生命周期
  • 闭包
    • 闭包的语法
    • 闭包的实现
    • 闭包作为参数和返回值
  • 集合类型 Collections
    • 动态数组 Vec
    • 哈希表 HashMap
  • 迭代器
    • 迭代器、适配器、消费者
  • 模块和包系统、Prelude
    • 模块 module 和包 crate
    • Prelude
  • Option、Result与错误处理
  • 输入与输出
  • 宏系统
  • 堆、栈与Box
  • 几种智能指针
    • Rc, Arc
    • Mutex, RwLock
    • Cell, RefCell
  • 类型系统中的几个常见 Trait
    • Into/From 及其在 String 和 &str 互转上的应用
    • AsRef, AsMut
    • Borrow, BorrowMut, ToOwned
    • Deref 与 Deref coercions
    • Cow 及其在 String 和 &str 上的应用
  • Send 和 Sync
  • 并发,并行,多线程编程
    • 线程
    • 消息传递
    • 共享内存
    • 同步
    • 并行
  • Unsafe、原始指针
    • Unsafe
    • 原始指针
  • FFI
    • rust调用ffi函数
    • 将rust编译成库
  • 运算符重载
  • 属性和编译器参数
    • 属性
    • 编译器参数
  • Cargo参数配置
  • 测试与评测
    • 测试 (testing)
    • 评测 (benchmark)
  • 代码风格
  • Any与反射
  • 安全(safe)
  • 常用数据结构实现
    • 栈结构
    • 队列
    • 二叉树
    • 优先队列
    • 链表
    • 图结构
  • 标准库介绍
    • 系统命令:调用grep
    • 目录操作:简单grep
    • 网络模块:W回音
  • 实战篇
    • 实战:Json处理
    • 实战:Web 应用开发入门
    • 实战:使用Postgresql数据库
  • 附录-术语表
Powered by GitBook
On this page
  • 函数类型
  • 函数作为参数
  • 函数作为返回值

Was this helpful?

  1. 函数

高阶函数

高阶函数与普通函数的不同在于,它可以使用一个或多个函数作为参数,可以将函数作为返回值。rust的函数是first class type,所以支持高阶函数。而,由于rust是一个强类型的语言,如果要将函数作为参数或返回值,首先需要搞明白函数的类型。下面先说函数的类型,再说函数作为参数和返回值。

函数类型

前面说过,关键字fn可以用来定义函数。除此以外,它还用来构造函数类型。与函数定义主要的不同是,构造函数类型不需要函数名、参数名和函数体。在Rust Reference中的描述如下:

The function type constructor fn forms new function types. A function type consists of a possibly-empty set of function-type modifiers (such as unsafe or extern), a sequence of input types and an output type.

来看一个简单例子:

fn inc(n: i32) -> i32 {//函数定义
  n + 1
}

type IncType = fn(i32) -> i32;//函数类型

fn main() {
  let func: IncType = inc;
  println!("3 + 1 = {}", func(3));
}

上例首先使用fn定义了inc函数,它有一个i32类型参数,返回i32类型的值。然后再用fn定义了一个函数类型,这个函数类型有i32类型的参数和i32类型的返回值,并用type关键字定义了它的别名IncType。在main函数中定义了一个变量func,其类型就为IncType,并赋值为inc,然后在pirntln宏中调用:func(3)。可以看到,inc函数的类型其实就是IncType。 这里有一个问题,我们将inc赋值给了func,而不是&inc,这样是将inc函数的拥有权转给了func吗,赋值后还可以以inc()形式调用inc函数吗?先来看一个例子:

fn main() {
  let func: IncType = inc;
  println!("3 + 1 = {}", func(3));
  println!("3 + 1 = {}", inc(3));
}

type IncType = fn(i32) -> i32;

fn inc(n: i32) -> i32 {
  n + 1
}

我们将上例保存在rs源文件中,再用rustc编译,发现并没有报错,并且运行也得到我们想要的结果:

3 + 1 = 4
3 + 1 = 4

函数作为参数

函数作为参数,其声明与普通参数一样。看下例:

fn main() {
  println!("3 + 1 = {}", process(3, inc));
  println!("3 - 1 = {}", process(3, dec));
}

fn inc(n: i32) -> i32 {
  n + 1
}

fn dec(n: i32) -> i32 {
  n - 1
}

fn process(n: i32, func: fn(i32) -> i32) -> i32 {
  func(n)
}

例子中,process就是一个高阶函数,它有两个参数,一个类型为i32的n,另一个类型为fn(i32)->i32的函数func,返回一个i32类型的参数;它在函数体内以n作为参数调用func函数,返回func函数的返回值。运行可以得到以下结果:

3 + 1 = 4
3 - 1 = 2

不过,这不是函数作为参数的唯一声明方法,使用泛型函数配合特质(trait)也是可以的,因为rust的函数都会实现一个trait:FnOnce、Fn或FnMut。将上例中的process函数定义换成以下形式是等价的:

fn process<F>(n: i32, func: F) -> i32
    where F: Fn(i32) -> i32 {
    func(n)
}

函数作为返回值

函数作为返回值,其声明与普通函数的返回值类型声明一样。看例子:

fn main() {
   let a = [1,2,3,4,5,6,7];
   let mut b = Vec::<i32>::new();
   for i in &a {
       b.push(get_func(*i)(*i));
   }
   println!("{:?}", b);
}

fn get_func(n: i32) -> fn(i32) -> i32 {
    fn inc(n: i32) -> i32 {
        n + 1
    }
    fn dec(n: i32) -> i32 {
        n - 1
    }
    if n % 2 == 0 {
        inc
    } else {
        dec
    }
}

例子中的高阶函数为get_func,它接收一个i32类型的参数,返回一个类型为fn(i32) -> i32的函数,若传入的参数为偶数,返回inc,否则返回dec。这里需要注意的是,inc函数和dec函数都定义在get_func内。在函数内定义函数在很多其他语言中是不支持的,不过rust支持,这也是rust灵活和强大的一个体现。不过,在函数中定义的函数,不能包含函数中(环境中)的变量,若要包含,应该闭包(详看13章 闭包)。 所以下例:

fn main() {
  let f = get_func();
  println!("{}", f(3));
}

fn get_func() -> fn(i32)->i32 {
  let a = 1;
  fn inc(n:i32) -> i32 {
    n + a
  }
  inc
}
Previous语句和表达式Next模式匹配

Last updated 5 years ago

Was this helpful?

这说明,赋值时,inc函数的所有权并没有被转移到func变量上,而是更像不可变引用。在rust中,函数的所有权是不能转移的,我们给函数类型的变量赋值时,赋给的一般是函数的指针,所以rust中的函数类型,就像是C/C++中的函数指针,当然,rust的函数类型更安全。可见,rust的函数类型,其实应该是属于指针类型(Pointer Type)。rust的Pointer Type有两种,一种为引用(Reference&),另一种为原始指针(Raw pointer *),详细内容请看。而rust的函数类型应是引用类型,因为它是安全的,而原始指针则是不安全的,要使用原始指针,必须使用unsafe关键字声明。

使用rustc编译,会出现如下错误:

Rust Reference 8.18 Pointer Types
error