RUST网络客户端的基本技术说明-函数和闭包

一、函数

在朴素的计算机语言中,函数几乎是整个程序编写的最小的单元,如果扣除对一些大型数据结构的认知,几乎要完成的所有的动作,都需要函数做底层的支持。发展到今天,仍然是如此。Rust必然也必须是把函数当成一个极其重要的环节来操作整个应用的实现。那在Rust中的函数和其它语言的函数应用有什么异同呢?
1、函数的声明

函数的声明如下形势:

fn FuncName()->() {
  //statements
}

整个函数以fn声明开始,后面跟函数名称和小括号包裹的参数定义,其后跟随的是返回值。

2、函数的参数和返回值

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

函数的参数是在函数名称后面用小括号包裹的,内部参数的定义如同普通变量的定义,其后的->后面指向的是返回值,如果返回值为(),则可以省略->(),这一点需要注意。
在Rust中,默认最后一个表达式的值为返回值,这和一些新兴语言类似。当然,函数也可以返回多个值:

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

同样也可以使用return返回值,或者说在Rust中仍然有这个关键字:

fn Display(n: i32) -> bool {
  if n != 10 {
    if n> 10 {
      return true;
    }
  }
  false
}

3、高阶函数
在Rust中,如果函数中以函数为参数或者以函数为返回值,那么就可以叫做高阶函数
看一下《RustPrimer》的例子:

fn main() {
  let xm = "xiaoming";
  let xh = "xiaohong";
  say_what(xm, hi);
  say_what(xh, hello);
}
fn hi(name: &str) {
  println!("Hi, {}.", name);
}
fn hello(name: &str) {
  println!("Hello, {}.", name);
}
fn say_what(name: &str, func: fn(&str)) {
  func(name)
}

同样,函数也可以是返回值(示例出自RustPrimer) :


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
    }
}

一般来说,函数名就是函数指针,这样理解可能会更容易让大多数人一下子明白。当然,高阶函数也可以用含有闭包来实现,看心情。

4、发散函数
发散函数(diverging function)以!号为结尾或者说返回类型,如下:

fn Err() -> ! {
 panic!("This function will never return");
}

5、方法(或者说其它语言的类函数)

Rust中没有Class这个关键字,但是有类似的实现,比如结构体、enum,当然还有Trait。在其中可以定义一些实现功能的函数,但在此处就叫做方法。简单来说,函数是发散的,可以任意定义在任何地方;而方法要有约束,一定会约束在指定的某个表述体内(即类形式的数据结构)。它通过impl实现方法的调用语法。
其第一个参数通常为self参数,它有三种表现形式:
1)允许操作者移动和修改对象,对应的闭包特性为FnOnce。
2)&self,既不允许操作者移动对象也不允许修改,对应的闭包特性为Fn。
3) &mut self,允许操作者修改对象但不允许移动,对应的闭包特性为FnMut。
如果函数中没有self参数的函数称为静态方法 (static method)。

struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}
impl Circle {
    fn new(x: f64, y: f64, radius: f64) -> Circle {
        Circle {
            x: x,
            y: y,
            radius: radius,
        }
    }
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}
fn main() {
    let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
    println!("{}", c.area());
    // use associated function and method chaining
    println!("{}", Circle::new(0.0, 0.0, 2.0).area());
}

示例出自RustPrimer。

二、闭包(匿名函数)

维基百科描述闭包:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是 引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
闭包的概念出现于60年代,最早实现闭包的程序语言是Scheme。之后,闭包被广泛使用于函数式编程语言如ML语言和LISP。很多命令式程序语言也开始支持闭包。
在离散数学里,闭包是实现某个运算闭合的最小集合。
二者其实可以想通的理解,看个人的理解方向角度和形式了。
看一下《RustPrimer》中的定义:

let plus_one = |x: i32| x + 1;
assert_eq!(2, plus_one(1));
或者:
let plus_two = |x| {
    let mut result: i32 = x;
    result += 1;
    result += 1;
    result
};
assert_eq!(4, plus_two(2));

如果想到向内部传递一个外部变量,在Rust中需要借用:

let mut num = 5;
{
    let plus_num = |x: i32| x + num;
} // plus_num goes out of scope, borrow of num ends
let y = &mut num;

如果在上面的代码中,没有使用大括号的话,会报一个,num已经被闭包借用,不能再次被借用的错误提示。

三、技术分析

重新回到最早的线程用法:

let handler = thread::spawn(move || {   
thread::sleep(Duration::from_secs(6));    
client_main();   
//thread::sleep_ms(2000);
});
//再看一个《RustPrimer》上的例子,对比一下就更明白了
let mut num = 5;
{
    let mut add_num = move |x: i32| num += x;
    add_num(5);
}
assert_eq!(5, num);

也就是说,move在匿名函数中的作用有几何?在上面的例子中,可以看到,通过这个关键字,可以把变量拷贝到闭包内去。打印的结果和普通的C/C++程序的全局变量和局部变量的同名机制解决方式雷同,在内部可变,但回到assert_eq!,又开始使用最初的值。仔细分析和对比,就对Rust中的所有权的控制,会有一个更清晰的了解。

四、总结

函数和闭包,用原话说叫“一等公民”,正如开始所说,这是编写Rust程序的最小单元,掌握一门语言就是从基础构件开始,而函数又是基础构件又是把各种基础构件有机结合在一起的基础构件。闭包说得有点高大上,其实就是为了实现函数式编程所预留的一个接口,指不定啥时候儿画风一转,就变成了函数式的开发方式,请好好想想吧。
努力吧,归来的少年!
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值