Rust中使用冒号的5种方式

在 Rust 中,冒号(:)用于不同的上下文。下面是 Rust 中冒号的一些常见用法:

1、类型注解:
在变量和函数参数声明中使用冒号来指定类型。
let x: i32 = 42;

在 Rust 中,当指定变量类型时,冒号在变量名后面而不是在类型名前面:
它来自类型理论。这是简单类型 lambda calc 中的数学符号,至今仍在更现代的类型理论中使用。
由于某种原因, Haskell 使用了双::代替冒号
它有点像集合符号。在哪里:

  • a ∈ A 表示“a 是集合 A 的元素”
  • a: A 表示“a 是类型 A 的项”

这是有道理的,因为类型的行为很像集合。
它保留在 Rust 中是因为它解析得很好,并且可以让你将像 'let' 'mut' 'const' 'fn' 等语言功能从类型系统中分离出来。

几乎所有现代函数编程语言(Go、Rust、Kotlin、Swift、Scala、Nim,甚至 Python 最新版本)中,类型总是出现在变量声明中的变量名称之后。

在标识符后面加上类型并不是一个新现象,它至少可以追溯到 Pascal(1968-1969 年设计,1970 年发布),但实际上在数学类型理论中使用,大约从 1902 年开始。它还被用于 ML (1973)、CLU (1974)、Hope (1970s)、Modula-2 (1977–1985)、Ada (1980)、Miranda (1985)、Caml (1985)、Eiffel (1985)、Oberon (1986)、Modula-3 (1986–1988) 和 Haskell (1989)


2、结构体字段类型注解:
结构体字段声明中使用冒号来指定字段类型。

struct Point {
    x: f64,
    y: f64,
}


结构体初始化,分号用于为结构字段赋值:
let point = Point { x: 1.0, y: 2.0 };

我们可以使用带有 let 语句的struct模式将其拆分开来。

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 7 };

    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);
}

这段代码创建的变量 a 和 b 与 p 结构中 x 和 y 字段的值相匹配。


3、函数返回类型注解:
函数声明中使用冒号来指定返回类型。

fn add(x: i32, y: i32) -> i32 {
    x + y
}

4、Rust 格式字符串中的 {:?}
std::fmt解释:

  • {...}包围所有格式指令。 
  • :将正在格式化的事物的名称或序号(在本例中被省略,因此意味着“下一个事物”)与格式化选项分开。
  • 是?一个格式化选项,它触发使用std::fmt::Debug正在格式化的事物的实现
  • {:?}格式化传递给格式化宏的“下一个”值,并支持任何实现Debug

Debug特征是 Rust 中最常用的特征之一。它允许您在面向程序员的调试上下文中格式化输出。您通常使用它的方式是这样的:
let v = vec![1, 2, 3];
let s = format!("{:?}", v);

如果您想自定义Debug类型(例如结构体),您可以简单地使用derive如下:

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}
fn main() {
    let person = Person {
        name: String::from("John"),
        age: 30,
    };

    println!(
"{:?}", person);
}

在本例中,{:?}与 println! 宏一起用于打印 Person 结构。要使其生效,Person 结构必须使用 #[derive(Debug)] 来派生 Debug 特性。该特性为结构体提供了 fmt::Debug 特性的默认实现。

输出类似:
Person { name: "John", age: 30 }

在开发和调试过程中,{:?} 格式指定符尤其有用。它打印值的方式有助于调试。对于自定义类型,可以手动实现调试特质,自定义使用 {:?} 显示值的方式。

5、Rust 提倡双冒号 '::' 方法
双冒号::类似于命名空间访问器,又称为路径分隔符,您可以浏览模块或指定位置

  • std::io::stdin():路径由crates、modules和items组成。std是库,io是模块,stdin()是特定项目。
  • 调用对象的方法String::new()。因为对象可能位于模块本身中,完整路径将是std::string::String::new

符号 :: 根据其使用地点和方式可以表示不同的含义。请参阅此处的表 B-3:路径相关语法。然而,我们大多数人将其用作命名空间路径的最常见用例。

总结:符号 :: 是一种上下文context相关的语法。