原始类型

C语言的世界

原始类型这个概念应该很好理解,C里面的整型 、浮点型、char、指针,定长数组

为什么叫原始类型?在C语言里面,类型的概念并不完备,C里面基本除了原始类型 其余我们见到的应该只有struct 这一种自定义类型了,原始类型的解释 一般归编译器解释, 在编译阶段,决定应该给变量(总是有类型的) 分配的栈大小和存放位置

RUST原始类型

RUST的原始类型有:

整型:

  • i8/i16/i32/i64/i128: 有符号整数,数字表示该变量的bit数,下同
  • u8/u16/u32/u64/u128: 无符号整数
  • isize/usize: 非固定bit的整数,取决于平台(32位系统=i32/u32 64位系统=i64/u64)

浮点型:

  • f32/f64: 符合IEEE 754标准的浮点类型

布尔型:

  • bool: 值有 false/true两种

数组:

  • [T,N] :和C类似,指定一个类型,以及大小,数组是在栈上分配的

元组类型:

  • (A,B,C,D):元组类型可以包含不同类型,数量不能超过10

文本类型:

  • char: 字符类型 一个4byte的内存单元(符合UTF-8标准的字符类型,关于UTF-8请自行查阅资料)
  • str: 一个加强版本的[u8]类型(切片类型 见下)

原始指针类型: 原始指针类型访问 不受RUST 安全机制管理

  • *const T :指向类型T的常量指针 不能修改内容
  • *mut T: 指向类型T的可变指针 可以修改内容

函数指针类型:

  • fn: 后面我们再讲闭包的时候会带一下

目前为止,上面几种类型(除了str) 我们在其他语言中应该都见过了,这里的原始指针类型可能比较拗口,我们先理解为 普通指针就好(RUST 为了保证内存安全,对于指针严格管理 我们后续会讲)

切片类型:

  • [T] : 和数组定义很像,但是没有大小,切片类型是一个动态大小类型 DST 切片类型用来表示一段内存视图 我们后续会讲关于动态大小的事情

引用类型: 指针的一个变体

  • 共享引用: &T
  • 唯一直接(可变)引用: &mut T

单元类型:

  • (): 一个空类型,仅仅用来处理代表返回值是空的函数(比如一个空函数)

从不返回类型:

  • !: 一个小类型, 仅仅用来处理函数永远不会返回的类型(比如一个panic/死循环函数)

理解库方法类型

大家一般在讲类型的时候,会给出一些示例代码,这些示例代码不可避免会用到一些方法,我们需要知道,类型和 该类型支持的方法是两个部分,后者一般是在 rust基础库中实现的,而类型是原生编译器的定义

fn main() {
    /// i8::MAX 中的MAX 是在RUST core 库中为 类型定义的一个常量 
    assert_eq!(i8::MAX, __); 
    assert_eq!(u8::MAX, __); 

    println!("Success!");

    ///下面是源代码的实现: 位于: rust-src/core/num/mod.rs 
    impl i8 {
    int_impl! {
        Self = i8,
        ActualT = i8,
        UnsignedT = u8,
        BITS = 8,
        BITS_MINUS_ONE = 7,
        Min = -128,
        Max = 127,
        rot = 2,
        rot_op = "-0x7e",
        rot_result = "0xa",
        swap_op = "0x12",
        swapped = "0x12",
        reversed = "0x48",
        le_bytes = "[0x12]",
        be_bytes = "[0x12]",
        to_xe_bytes_doc = "",
        from_xe_bytes_doc = "",
        bound_condition = "",
    }
}   
}

另外,基础库里面也实现了大量的类型: String Vec HashMap这些,我认为这些不在我的笔记内容范围之内 这些类型的使用大部分可以通过查阅 API 文档手册 得到答案

本笔记更加关注的是背后的实现原理,而库中类型的实现,应该作为我们的一个代码参考,看RUST社区高手是如何 利用RUST特性开发的

目前的难点

在类型介绍中,我们可能已经遇到了从来没有见过的术语,而这些术语的出现,是由于RUST 设计原则以及为了保证 安全才诞生的,如果和其他语言都一样,那RUST就没有特殊性了

我们会在后续的笔记中,逐步对里面的内容展开 相信你不会失望

数字变量的使用

再阅读本节之前,建议先阅读完下一章节 再回来看,本节会用到下一节的知识

整性变量可以使用:

  • 单位表达式 100_000
  • 可以使用 _ 声明类型
  • 可以使用 0x:16进制 0o:八进制 0b:2进制

练习1: 类型

fn main() {
    // 标准的变脸声明: let variable: type = value;
    let a: i32 = 1;
    is_i32(a);
    // 数字类型支持通过 *_*显示声明类型 尝试修复它 
    let b: i32 = 2_u32;
    is_i32(b);
    // RUST支持默认类型推导,该推导发生在编译阶段,整性默认类型为i32 
    let c = 3;
    is_u32(c);
    let d = 4_u32; 
    is_i32(c);

    // 浮点类型默认类型是f64 尝试修复它
    let e = 1.0;
    is_f32(e);
    let f = 1.0_f64;
    is_f64(e);
}

fn is_i32(val: i32) -> () {}
fn is_u32(val: i32) -> () {}
fn is_f32(val: f32) -> () {}

练习2: 进制表达式

// Modify `assert!` to make it work
fn main() {
    let v = 1_024 + 0xff + 0o77 + 0b1111_1111;
    assert!(v == 1579);

    println!("Success!");
}

字符类型的使用

  • 字符类型是UTF-8编码的,也就意味着代表的内存是4字节大小
  • 变量需要使用 '' 和C 一样

练习1: 关于内存大小


// Make it work
use std::mem::size_of_val;
fn main() {
    let c1 = 'a';
    assert_eq!(size_of_val(&c1),1); 

    let c2 = '中';
    assert_eq!(size_of_val(&c2),3); 

    println!("Success!");
} 

练习2: 关于声明


// Make it work
use std::mem::size_of_val;
fn main() {
    let c1 = 'a';
    assert_eq!(size_of_val(&c1),1); 

    let c2 = '中';
    assert_eq!(size_of_val(&c2),3); 

    println!("Success!");
} 

数组的使用

和C基本上是一样的

  • 数组类型声明为 [TYPE:SIZE]
  • 可以使用 [val;size] 的方式一次性初始化数组内存
  • 为了保证数组内存大小的计算, 数组元素类型必须是相同的,
  • 通过数组下标访问元素
  • 通过数组下标访问的元素 必须是要支持 copy 特征的(暂时先不用关注)
 fn main() {
    // Fill the blank
    let list: [char; 100] = ['a';100] ;

    assert!(list[0] == 'a');
    assert!(list.len() == 100);

    println!("Success!");
}