• Rust中的变量默认是不可变的, 但是可以添加mut关键字使之可变

    Rust有单次赋值(Single assignment)原则, 尽管Rust变量默认是不可变的, 但是它允许你在声明变量后延迟赋值一次, 只要编译器能确定该变量只会被赋值一次即可.

    1
    2
    3
    4
    5
    6
    7
    // 下面的语句是可以通过编译的
    let x;
    if cond {
    x = 1;
    } else {
    x = 2;
    }
  • 常量声明方式:

    1
    const THREE_HOURS_IN_SENCONDS: u32 = 60 * 60 * 3;

    常量不允许使用mut关键字来修饰, 也就是说常量是不可改变的.

    常量存活在程序运行的整个生命周期, 也就是说在常量定义的范围内一直生效

  • Shadowing: 新变量覆盖了旧变量,导致在特定作用域内旧变量的值不可见

  • 数据类型

    整形:DataType

    其中,有符号数采用二进制补码存储, isizeusize取决于计算机的架构

    另外编译的时候,如果使用debug模式, 编译器会检查整形溢出. 但是如果采用release模式, 则不会进行溢出检查, 而是会类型回绕

浮点数: 默认为f64, 根据IEEE-754标准表示

布尔类型: true false

字符类型: 一个Rust字符占4字节, 可以表示其他语言, 并且零宽空格也是有效的char值

元组类型: 固定长度, 元组中的元素类型不必相同

1
let tup: (i32, f64, u8) = (500, 6.4, 1);

​ 可以通过模式匹配(pattern matching)解构元组值:

1
2
3
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is {y}");

​ 也可以通过点(.)来获取每个位置的元素

1
2
3
4
let x: (i32, f64, u8) = (500, 6.4, 1);
let one = x.0;
let two = x.1;
let three = x.2;

​ 空元组也叫单元(unit), 这个值及对应类型都写作(), 代表空值或者空返回类型.如果表达式没有返回其他任何值, 则隐式返回单元值.

数组类型: 固定长度, 每个元素类型都相同

​ 声明方式:

1
2
3
4
5
6
let months = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];

let a: [i32; 5] = [1, 2, 3, 4, 5]; // 声明为5个i32类型

let a = [3; 5]; // 生成5个3

​ 可以通过中括号声明, eg: months[1], month[2] st.

  • Statements(语句) 和 Expressions(表达式)

    • 语句是执行某些操作但不返回值的操作

      • let 绑定

        1
        let x = 5;
      • 表达式语句

        1
        2
        let y = 6;
        y + 1; // 这是一个语句, y + 1的结果被丢弃了
      • 函数定义

      • 宏调用(作为语句): println!("Hello, world!"); (虽然 println! 是一个宏,但当它用作打印输出时,通常作为不返回值的语句使用)

      • 任何以分号结尾的表达式:

    • 表达式是 Rust 中会计算并产生一个值的代码块。它们可以由字面量、变量、运算符、函数调用、宏调用,甚至由花括号包围的代码块组成。可以用于赋值, 并且通常不以分号结尾, 如果以分号结尾,它就会变成一个语句, 其返回值会被丢弃.

      1
      2
      3
      4
      5
      let y = {
      let x = 3;
      x + 1 // 这是一个表达式, 返回4
      };
      // now y is 4

    总结区别

    特性 表达式 (Expressions) 语句 (Statements)
    返回值 会返回值 不返回值
    结尾 通常不以分号结尾(在作为代码块的最后一行时) 通常以分号结尾
    目的 计算并产生一个值 执行一个操作
    例子 1 + 2, { let x = 3; x + 1 }, if cond { 1 } else { 0 } let x = 5;, println!("Hello!");, x = 10;
  • 函数

    声明方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    fn main() {
    println!("hello, wworld!");

    another_funtion();
    }

    fn another_funtion(x: i32) { // 必须定义函数形参的类型
    prinlin!("Another funtion.");
    println!("The value of x is: {x}");
    }

    fn plus_one(x: i32) {
    x + 1
    }

    fn f(x: i32) -> i32 { // 有返回值的函数
    x + 1
    // return x + 1; // 显式返回也可以
    }

    Rust不在乎在哪里定义函数(调用前, 调用后), 只要函数被定义在调用者可以看到的作用域中即可.

  • 控制流

    • 条件控制

      1
      2
      3
      4
      5
      6
      7
      8
      9
      fn main() {
      let number = 3;

      if number < 5 { // if 后面一定是跟一个bool类型, 如果是其他类型并不会隐式转换为bool类型
      println!("condition was true");
      } else {
      println!("condition was false");
      }
      }
      1
      2
      3
      4
      5
      6
      7
      fn main() {
      let condition = true;

      let number = if condition { 5 } else { 6 }; // 这里的两个分支都必须是相同的类型, 不然会报错

      println!("The value of number is {number}. ");
      }

      因为Rust需要在编译时需要知道变量的类型, 而不是运行时再做推断, 所以如果使用上面的语句来进行赋值的时候, 不同分支返回的都必须是相同的类型.

    • 循环

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      fn main() {
      let mut cnt = 0;
      let result = loop {
      cnt += 1;

      if cnt == 10 {
      break cnt * 2; // 使用break 中断循环并且返回值
      };
      }

      println!("The result is {result}");
      }

      如果有嵌套循环, 可以通过标签来标注某个特定的循环并且可以break掉特的循环:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      fn loopwithlabels() {
      let mut cnt = 0;
      'counting_up: loop { // 使用单引号来声明一个标签
      println!("cnt = {cnt}");
      let mut remaining = 10;

      loop {
      println!("remaining = {remaining}");
      if remaining == 9 {
      break;
      }
      if cnt == 2 {
      break 'counting_up;
      }
      remaining -= 1;
      }

      cnt += 1;
      }

      println!("End cnt = {cnt}");
      }

      while 循环: 与其他语言十分相似

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      fn main() {
      let mut number = 3;

      while number != 0 {
      println!("{number}");

      number -= 1;
      }

      println!("LIFTOFF!!");
      }

      遍历集合:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      /* 通过while循环来遍历 */
      fn main() {
      let a = [10, 20, 30, 40, 50];
      let mut idx = 0;

      while idx < 5 {
      println!("the value is {}", a[idx]);

      idx += 1;
      }
      }

      /* 通过for循环遍历, 推荐 */
      fn main() {
      let a = [10, 20, 30, 40, 50];

      for element in a {
      println!("the value is {element}");
      }
      }

  • 一般crate使用use导入, 但是Rust会自动导入prelude,里面包含了基本的功能, 详见standard library documentation.

  • Rust中的变量默认是不可变的, 可以添加mut关键字使之改变

  • read_line读取用户输入,并将其添加到字符串尾端(append), 而不是覆盖, 不同于cin

  • read_line会返回一个Result值

  • Result是一个枚举类型,其中有OkErr, 所以可以使用read_line(&mut guess).expect("Failed to read") expect函数来处理错误读入, 任何类型的值都有其方法

  • 正常情况下,expect()方法会返回用户输入的字节数

  • println!() 可以使用{}来输出变量, 但是如果变量名称不存在就会报错

  • crate是一组Rust源代码文件,用户构建的项目是一个二进制crate, 它是一个可执行文件. rand crate是一个库crate, 它包含的代码用于其他程序, 并不能单独运行

    阅读全文 »

此分类(The Rust Programming Language)采用brown university的实验版本, 对细节进行解释同时进行学习记录

image-20250616162739328

Getting Started

  • rustup 来管理机器上的Rust版本

  • rustc main.rs				// rustc的用法, rustfmt也可以这么使用
    rustfmt main.rs				// 使用rust的语法格式化文档
    ./main
    
  • cargo init: 自动获取cargo.toml文件\

  • cargo.lock文件追踪准确的版本依赖

  • cargo run 只有代码发生改变的时候才会重新编译运行, 否则直接运行

  • cargo build --release会在target/release下生成目标文件, 会让Rust代码运行更快,没有debug. 如果要衡量代码效率就是用此命令编译

    阅读全文 »

一个简单的时间获取客户程序

本系统: Debian 12

如何下载源码并编译运行

官方源码地址:https://github.com/unpbook/unpv13e

git clone https://github.com/unpbook/unpv13e.git

克隆到本地之后,根据README文件一步一步make配置

接下来可以直接 make 想要运行的源码 然后执行即可

阅读全文 »

引言

最近在开发项目的时候碰到了领域模型,但是并没有对其中的各层关系以及各层传递数据方式理解清晰。在此记录下分层领域模型数据的传递过程

所谓领域模型

所谓领域模型,其实就是C++类,再详细一点就是有作用范围的实体类。

其核心目标是业务抽象:将现实业务中的实体、流程和规则转化为可被代码理解和操作的结构。

其中的领域对象描述是这样的:

  • DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
  • DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。
  • BO(Business Object):业务对象,可以由 Service 层输出的封装业务逻辑的对象。
  • Query:数据查询对象,各层接收上层的查询请求。
  • VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。

img

阅读全文 »

前情提要

野指针(Wild Pointer): 野指针是指指向任意未知位置的指针,它没有被初始化或者指向无效的内存。

悬挂指针(dangling pointer):指指向已释放或无效内存的指针。当一个指向动态分配内存的指针所指向的内存被释放后,该指针仍然保留着原来的指向,但此时使用该指针访问所指向的内存将导致未定义的行为。

RAII (Resource Acquisition Is Initialization): 资源获取即初始化, R使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。像下面的例子:

阅读全文 »

一些基本概念

CORS(跨域资源共享):浏览器的安全特性,允许你控制哪些外部域名访问你的API

API路由:简单来说就是根据客户端发起的请求(包括请求的方法,如GET、POST、PUT等,以及请求的URL路径)将请求映射到不同的处理逻辑中:

1.匹配客户端发来的请求

2.根据请求的路径和方法,找到并执行相应的代码(处理逻辑)

3.返回一个响应给客户端

阅读全文 »

前两天突发奇想想把一直在用的实机(Debian 12)换成Anolis OS,在安装这个系统的时候碰到了不少问题,现记录于此.

机器配置:

笔记本品牌: HUAWEI MateBook D 14

CPU型号: R5 4500U

内存: DDR4 16GB 2666MHz

硬盘: SSD 512GB

网络通信: Realtek RTL8821CE/RTL8822CE Wi-Fi

安装:

准备: 至少16GB的U盘

  1. Anolis官网下载需要的镜像

  2. 通过u盘刻录软件将镜像刻录到U盘(我用的是rufus), 其中刻录的时候要注意的是:

    1.分区类型(MBR或GPT)一定要选择与系统相匹配的类型, MateBook D 14要选择GPT,不然会导致启动u盘的时候被验证失败(Error: Vertification failed).

    2.写入模式要选择DD模式, 不要选择ISO模式, 不然会导致进入安装界面的时候本地仓库识别不到.

  3. 最后根据引导完成安装即可.

    阅读全文 »

闲来无事刷个题目用所有方法解一遍斐波那契,没想到在记忆化翻车了

呆码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int fib(int n) {
vector<int> memo(n + 1, -1);
memo[0] = 0;
memo[1] = 1;

function<int(int)> mdfs = [&](int i) -> int {
if(i <= 1) return i;

if(memo[i] != -1) return memo[i];

memo[i] = mdfs(i - 1) + mdfs(i - 2);

return memo[i];
};

return mdfs(n);
}
阅读全文 »
0%