队列简介队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。在队列的形成过程中,可以利用线性链表的原理,来生成一个队列。
栈简介栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。
本章讲解如何使用 Rust 进行一些常用数据结构的实现。实现的代码仅作示例用,并不一定十分高效。真正使用的时候,请使用标准库或第三方成熟库中的数据结构。
本章不讲解任何语言知识点,而是对 Rust 安全理念的一些总结性说明。安全,本身是一个相当大的话题。安全性,本身也需要一个局部性的定义。Rust 的定义中,凡是 可能 会导致程序内存使用出错的特性,都被认为是 不安全的(unsafe)。反之,则是 安全的(safe)。基于这种定义,C 语言,基本是不安全的语言(它是众多不安全特性的集合。
熟悉Java的同学肯定对Java的反射能力记忆犹新,同样的,Rust也提供了运行时反射的能力。但是,这里有点小小的不同,因为 Rust 不带 VM 不带 Runtime ,因此,其提供的反射更像是一种编译时反射。因为,Rust只能对 'static 生命周期的变量(常量)进行反射!举个例子我们会有这样的需求,去某些路径里加载配置文件。
空白每行不能超出99个字符。缩进只用空格,不用TAB。行和文件末尾不要有空白。空格二元运算符左右加空格,包括属性里的等号:#[deprecated = "Use `bar` instead."]fn foo(a: usize, b: usize) -> usize { a + b}在分号和逗号后面加空格:fn foo(a: Bar);MyStruct { foo: 3, bar: 4 }foo(bar, baz);
单元测试是用来校验程序的正确性的,然而,程序能正常运行后,往往还需要测试程序(一部分)的执行速度,这时,f就需要用到性能测试。通常来讲,所谓性能测试,指的是测量程序运行的速度,即运行一次要多少时间(通常是执行多次求平均值)。Rust 竟然连这个特性都集成在语言基础特性中,真的是一门很重视工程性的语言。下面直接说明如何使用。
程序测试是一种找到缺陷的有效方式,但是它对证明没有缺陷却无能为力。Edsger W. Dijkstra, "The Humble Programmer" (1972)作为软件工程质量保障体系的重要一环,测试是应该引起我们充分注意并重视的事情。前面说过,Rust 语言的设计集成了最近十多年中总结出来的大量最佳工程实践,而对测试的原生集成也正体现了这一点。下面来看 Rust 是怎么设计测试特性的。
本章讲解 Rust 中内建的测试与评测相关知识。
我们在使用toml描述文件对项目进行配置时,经常会遇到项目版本声明及管理的问题,比如:[package]name = "libevent_sys"version = "0.1.0"[dependencies]libc = "0.2"这里package段落中的version字段的值,以及dependencies段落中的libc字段的值,这些值的写法,都涉及到语义化版本控制的问题。语义化版本控制是用一组简单的规则及条件来约束版本号的配置和增长。
本章将介绍Rust编译器的参数。Rust编译器程序的名字是rustc,使用它的方法很简单:$ rustc [OPTIONS] INPUT其中,[OPTIONS]表示编译参数,而INPUT则表示输入文件。而编译参数有以下可选:-h, --help - 输出帮助信息到标准输出;--cfg SPEC - 传入自定义的条件编译参数,使用方法如fn main() { if cfg!(hello) { println!("world!");
属性(Attribute)是一种通用的用于表达元数据的特性,借鉴ECMA-334(C#)的语法来实现ECMA-335中描述的Attributes。属性只能应用于Item(元素、项),例如 use 声明、模块、函数等。元素在Rust中,Item是Crate(库)的一个组成部分。
本章将介绍Rust语言中的属性(Attribute)和编译器参数(Compiler Options)。
Rust可以让我们对某些运算符进行重载,这其中大部分的重载都是对std::ops下的trait进行重载而实现的。重载加法我们现在来实现一个只支持加法的阉割版复数:use std::ops::Add;#[derive(Debug)]struct Complex { a: f64, b: f64,}impl Add for Complex { type Output = Complex; fn add(self, other: Complex) ->
上一章讲述了如何从rust中调用c库,这一章我们讲如何把rust编译成库让别的语言通过cffi调用。调用约定和mangle正如上一章讲述的,为了能让rust的函数通过ffi被调用,需要加上extern "C"对函数进行修饰。但由于rust支持重载,所以函数名会被编译器进行混淆,就像c++一样。因此当你的函数被编译完毕后,函数名会带上一串表明函数签名的字符串。
下文提到的ffi皆指cffi。Rust作为一门系统级语言,自带对ffi调用的支持。Getting Start引入libc库由于cffi的数据类型与rust不完全相同,我们需要引入libc库来表达对应ffi函数中的类型。在Cargo.toml中添加以下行:[dependencies]libc = "0.2.9"在你的rs文件中引入库:extern crate libc在以前libc库是和rust一起发布的,后来libc被移入了crates.io通过cargo安装。
FFI(Foreign Function Interface)是用来与其它语言交互的接口,在有些语言里面称为语言绑定(language bindings),Java 里面一般称为 JNI(Java Native Interface) 或 JNA(Java Native Access)。
Rust通过限制智能指针的行为保障了编译时安全,不过仍需要对指针做一些额外的操作。*const T和*mut T在Rust中被称为“裸指针”。它允许别名,允许用来写共享所有权的类型,甚至是内存安全的共享内存类型如:Rc<T>和Arc<T>
Rust的内存安全依赖于强大的类型系统和编译时检测,不过它并不能适应所有的场景。首先,所有的编程语言都需要跟外部的“不安全”接口打交道,调用外部库等,在“安全”的Rust下是无法实现的; 其次,“安全”的Rust无法高效表示复杂的数据结构,特别是数据结构内部有各种指针互相引用的时候;再次,事实上还存在着一些操作,这些操作是安全的,但不能通过编译器的验证。
本章开始讲解 Rust 中的 Unsafe 部分。
关注时代Java