搬迁难度说明

  • ⭐️ —— 简略,简直无搬迁本钱

  • ⭐️⭐️ —— 适中,略微留意下两者差异即可

  • ⭐️⭐️⭐️ —— 较难,需求一定的编码经验,可经过凭借编译器的过错提示习气

超越 ⭐️ 的难度,可要点留意「搬迁难点」高亮块。

若有任何疑问或错漏,欢迎随时交流纠正。

介绍

Rust 和 Swift 相同都是现代化的年青编程言语,言语特性上都学习了很多不同言语的优点,语法上有诸多相似的当地,不过诞生的布景和方针不相同,所以也有差异很大的当地,有着不同的运用场景。

Swift 诞生在 Apple,2014 年发布 1.0 版别,在 WWDC 2015 开发者大会宣布开源,并于同年发布 2.0 版别。因而,Swift 开始的方针根本便是取代 Objective-C 成为苹果渠道的下一代官方编程言语,在安全、快速这样的根底上,致力于易学、易上手,以促进渠道运用的进一步昌盛。之后的开源并推及到 Linux 渠道和服务端,根本也是这个方针的延展。

Rust 诞生于 Mozilla,按 1.0 版别发布的话,比 Swift 还年青 1 岁,2015 年发布的 1.0 版别。Mozilla 开源布景和前史,以及在社区上的经验和积累是非常丰富的,因而 Rust 从开始就由良好的开源社区驱动,方针是成为安全可靠且高功能的体系级编程言语。既然是体系级言语,则对标的是 C 和 C++,无运行时和垃圾收回,保证功能的同时,能够便利地进行跨渠道和嵌入式开发。

Rust 中最大的思想转化是变量的所有权和生命周期,一种简直其他编程言语都不太涉及的内存办理机制。除此之外,对于了解 Swift 的开发者,在通用言语层面和编程范式层面并没有太大差异。

因而,作为一名从 iOS 转 Rust SDK 的开发者,我将结合 Swift 的以往运用经验以及对 Rust 的学习爬坑体会,从客户端工程师的视角,经过以下这些方面和组织结构对两门言语进行对比学习,杰出重难点,帮助我们一同基于 Swift 的经验快速向 Rust 搬迁。

根底篇

变量绑定

可变性

搬迁本钱:⭐️

Rust 和 Swift 都默许引荐不行变优先,并清晰声明可变性。

// Rust
let x = 666; 
// 默许不行变
// x = 999; <- 编译会报错
let mut y = 233; // let mut 清晰声明可变性
y = 23333; // <- 编译经过
// Swift
let x = 666
var y = 233

效果域和遮盖(shadowing)

搬迁本钱:⭐️

Rust 和 Swift 相同,变量绑定的效果域都被限定在一个代码块中。

// Rust
fn main() {
  let long_lived_binding = 1; // 效果域为整个 main 函数
  {
    let short_lived_binding = 2; // 仅效果域当时代码块中
    println!("{}", short_lived_binding); // 打印 2
  }
  // 报错:cannot find value `short_lived_binding` in this scope
  println!("{}", short_lived_binding);
  println!("{}", long_lived_binding); // 打印 1
}
// Swift
func main() {
    let longLivedBinding = 1
    do {
        let shortLivedBinding = 2
        print(shortLivedBinding)
    }
          // 报错:Use of unresolved identifier 'shortLivedBinding'
    print(shortLivedBinding)
    print(longLivedBinding) // 打印 1
}

和 Swift 有所差别的是, Rust 还支撑变量遮盖,Swift 仅在可选型拆包时支撑变量遮盖。

// Rust
let x = 1;
let x = 2; // 此刻 x 的绑定会遮盖上一个 `x` 的绑定
println!("{}", x); // 打印 2
// Swift
let x = 1
let x = 2 // 报错:Definition conflicts with previous value
// 仅支撑可选型的拆包“遮盖”
let x: Int? = 1
print(x) // 打印:Optional(1)
if let x = x {
    print(x) // 打印 1, 此刻 x 不再是可选型而是实际内容
}

类型体系

要害点:Rust 和 Swift 在理念上,均面向类型安全规划,经过强壮的类型体系,在编译时保障软件安全,尽可能防止运行时溃散或未界说行为。

From Swift to Rust - The Fast Way(基础篇)

强类型&静态类型

搬迁本钱:⭐️

和 Swift 相同,Rust 也是一门强类型+静态类型编译型言语。

  • 强类型:一旦变量被指定类型,除非强制转化,不然一直为该类型

  • 静态类型:编译期间履行类型查看,防止类型过错

// Rust
let x: u8 = 200;
let y: u8 = 100;
// Swift
let x: Int = 200
let y: Int = 100

类型推导

搬迁本钱:⭐️

Rust 和 Swift 均具有类型推导才能

// Rust
let x = 2.0; // 主动类型推导:f64
let y: f32 = 3.0; // 显示声明类型:f32
// Swift
let x = 2.0 // Double
let y: Float = 3.0 // Float

类型转化(Type cast)

搬迁本钱:⭐️

与 Swift 相似,Rust 不提供原生类型之间的隐式类型转化,而是运用 as 要害字进行显式转化。

// Rust
let decimal = 3.14_f32;
// 不支撑隐式类型转化,报错:mismatched types
let integer: u8 = decimal; 
let integer = decimal as u8; // 支撑显式转化
// Swift
let decimal = 3.14
// 不支撑隐式类型转化,报错:Cannot convert value of type 'Double' to specified type 'Int'
let integer: Int = decimal
let integer = Int(decimal)
let thing1: Int = Int(89.0) as Int
let thing2: Float = 1 as Float

差异留意点

  • Rust:

    • as 可能丢掉精度(类比 C/C++ 中的隐式转化),且仅支撑原始类型的显式声明转化
    • 由于没有 class 也就没有承继,因而无需 down_cast 的场景
    • 对于自界说类型转化,一般选用完成 From traitInto trait 的办法
    • as 要害字还可与 use 合作运用:use std::mem as memory;
  • Swift:

    • as 仅在不丢掉精度的状况下可用,其他状况须运用类型结构办法。
    • as!as? 更多的运用场景是 class 承继中的 down_cast。

值语义 v.s 引证语义

搬迁本钱:⭐️⭐️

Rust 中自界说类型只有 enum 和 struct,和 Swift 相同均默许为值语义。无 class 类型,因而引证语义需经过& **借用(Borrowing)**或合作智能指针显式声明。

// Rust
// 留意 `let mut`、`&mut` 的运用
#[derive(Debug)]
struct Foo {
    x: u8
}
fn change_foo_val(foo: &mut Foo, val: u8) {
    foo.x = val;
}
fn main() {
    let mut foo = Foo { x: 1 };
    change_foo_val(&mut foo, 9);
    println!("foo: {:?}", foo); // 输出:foo: Foo { x: 9 }
}
// Swift
// 留意 `var`、`inout`、`&` 的运用
struct Foo {
    var x: Int
}
func changeFooVal(_ foo: inout Foo, to val: Int) {
    foo.x = val
}
var foo = Foo(x: 1)
changeFooVal(&foo, to: 9)
print("foo: \(foo)") // 输出:foo: Foo(x: 9)`

搬迁难点

与 Swift 中的值语义默许支撑 CoW(Copy on Write)不同,Rust 中除非显式声明其Copy trait(能够简略了解为声明后就支撑 CoW 了),不然默许是「所有权搬运」语义,这在后边「内存办理」一节中的所有权机制中会详细介绍。

值语义

Swift 中有结构体(struct)和枚举(enum)两种值语义的自界说类型,Rust 中也相似。

结构体(Struct)
// Rust
// 声明
struct Point {
    x: f32,
    y: f32,
}
// 运用`impl`要害字来完成办法
impl Point {
  fn new() -> Self {
    Self { x: 0.0, y, 0.0 }
  }
}
// 初始化
let point = Point { x: 0.5, y: 0.5 };
let oringin = Point::new();
// 支撑解构
let Point { x: the_x, y: the_y } = point;
println!("{}, {}", the_x, the_y); // 打印:0.5, 0.5
// Swift
struct Point {
    let x: Float
    let y: Float
}
let point = Point(x: 0.5, y: 0.5)
枚举(Enum)

与 Swift 相似,Rust 中枚举也支撑相关值

// Rust
enum CustomError {
  CustomError1,
  CustomError2,
  CustomError3
}
// 相关值枚举
enum CustomError {
  CustomError1(&str),
  CustomError2(u32),
  CustomError3(&str, u32)
}
// Swift
enum CustomError {
  case customError1
  case customError2
  case customError3
}
// 相关值枚举
enum CustomError {
  case customError1(String)
  case customError2(UInt)
  case customError3(String, UInt)
}

引证语义

Swift 中有类(class)来声明引证语义的自界说类型。但在 Rust 中没有类的概念,要运用引证语义,需求在值语义类型之上经过规范库中的 Box<T> 、 Rc<T> 、Arc<T> 等智能指针进行「封装」。

见「智能指针」小节

数据类型

搬迁本钱:⭐️⭐️

原始类型(Primitive Types)

Rust 与 Swift 的原始数据类型根本共同,仅以整型示例,其他根本都无缝转化。

组合类型(Compund Types)

元组(Tuples)
// Rust
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 形式匹配
let (x, y, z) = tup;
println!("The value of y is: {}", y);
// Swift
let tup: (UInt32, Double, UInt8) = (500, 6.4, 1)
// 形式匹配
let (x, y, z) = tup
print("The value of y is: \(y)")
数组(Arrays)
// Rust
let a = [1, 2, 3, 4, 5];
// 类型声明
// :5 表明该数组为 5 个元素,编译时静态确定,属于类型的一部分
let b: [i32; 5] = [1, 2, 3, 4, 5];
let c = [3; 5]; // 等价:let c =[3, 3, 3, 3, 3]
// 元素拜访
let first = a[0];
let second = a[1];
// 数组拜访越界
// 编译过错:error: this operation will panic at runtime
let six = a[5]; 
//       ^^^^ index out of bounds: the length is 5 but the index is 5
// Swift
let a = [1, 2, 3, 4, 5]
// 类型声明
let b: Array<Int32> = [1, 2, 3, 4, 5]
let b2: [Int32] = [1, 2, 3, 4, 5]
// 元素拜访
let first = a[0]
let second = a[1]
// 数组拜访越界
// 运行时溃散:Fatal error: Index out of range
let six = a[5]

搬迁难点

  • 与 Swift 中的数组支撑动态扩容不同,Rust 中的数组与 C 中的数组更相似,仅支撑静态巨细。size 是其类型的一部分,相同类型不同巨细的数组是不同的数据类型,且不支撑动态扩容。因而,Rust 能够很好地防止运行时数组拜访越界。
  • 若需求支撑动态扩容,运用 Vec<T> 类型

相关数据类型(Related Data)

结构体(Structs)

Rust 与 Swift 中的 struct 在语法层面非常相似。只需留意细微的一些差异即可:

  • 属性声明不区别可变性,与结构体变量全体共用可变性;

  • 默许结构办法属于 C 系风格,一般会额定自界说 fn new 相关办法(可选);

  • Rust 支撑「元组风格结构体」(tuple struct)

  • Rust 支撑「单位类型结构体」(unit-like)

  • Rust 的结构体在相关存储引证类型时,须格外留意所有权和生命周期问题

惯例运用
// Rust
// 界说声明
struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}
// 初始化结构
let mut user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};
// Getter&Setter 均支撑点语法
user1.email = String::from("anotheremail@example.com");
// Swift
struct User {
    var active: Bool
    var username: String
    var email: String
    var sign_in_count: UInt64
}
// 初始化结构
var user1 = User(active: true, username: "someusername123", email: "someone@example.com", sign_in_count: 1)
// Getter & Setter
user1.email = "anotheremail@example.com"
元组结构体(Tuple struct)
// Rust
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
}
单位结构体(Unit struct)
// Rust
struct AlwaysEqual;
fn main() {
    let subject = AlwaysEqual;
}
所有权与生命周期标示

再一次触及到 Rust 要害点,先有个形象,后边内存办理一节中的所有权机制中会继续详细介绍。

生命周期标示,是为了让编译器保证结构体内部引证的数据不会早于当时结构体开释,防止悬垂指针的内存问题导致溃散。

// Rust
// 未标示生命周期,报错
// error[E0106]: missing lifetime specifier
struct User {
    active: bool,
    username: &str,
    //        ^ expected named lifetime parameter
    email: &str,
    //        ^ expected named lifetime parameter
    sign_in_count: u64,
}
// 标示生命周期,经过编译
struct User<'a> {
    active: bool,
    username: &'a str,
    email: &'a str,
    sign_in_count: u64,
}
fn main() {
    let user1 = User {
        email: "someone@example.com",
        username: "someusername123",
        active: true,
        sign_in_count: 1,
    };
}
枚举(Enum)
// Rust
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
impl Message {
    fn call(&self) { /*do call*/ }
}
let m = Message::Write(String::from("hello"));
m.call();
// Swift
enum Message {
    case quit
    case move(x: Int32, y: Int32)
    case write(String)
    case changeColor(Int32, Int32, Int32)
}
extension Message {
    func call() { /*do call*/ }
}
let m = Message.write("hello")
m.call()

深化学习数据类型:doc.rust-lang.org/book/ch03-0…

面向过程

操控流

搬迁难度:⭐️⭐️

条件操控

Rust 和 Swift 以及绝大多数言语相同,运用 if/else 进行条件操控。

需求额定留意的点是 Rust 中全部皆表达式,不支撑惯例的三目运算符,也是用 if/else 表达。

// Rust
let is_super = true;
let a = if is_super { u32::MAX } else { u32::MIN };
// Swift
let isSuper = true
let a = isSuper ? Int32.max : Int32.min

循环

Rust 中循环提供 loop、while、for/in 三种办法,和 Swift 非常相似

  • loop:无限循环,运用 break 退出或 continue 跳入下一个迭代
// Rust
let mut count = 0;
loop {
  count += 1;
  if count == 3 {
    continue; // 跳过后续履行直接进入下个迭代
  }
  println!("{}", count);
  if count == 5 {
    break; // 退出循环
  }
}
// swift
var count = 0
repeat {
    count += 1
    if count == 3 {
        continue
    }
    print(count)
    if count == 5 {
        break
    }
} while true

Rust 中 loop 的嵌套是支撑标签注明的,break 时默许退出当时循环,能够标识标签来直接退出外层循环。

'outer: loop {
    println!("Entered the outer loop");
    'inner: loop {
        println!("Entered the inner loop");
        // 默许只是中止内部的当时循环
        //break;
        // 直接会中止外层循环
        break 'outer;
    }
    println!("This point will never be reached");
}
println!("Exited the outer loop");

除此之外,loop 还支撑经过 break 返回值。

let mut counter = 0;
let result = loop {
    counter += 1;
    if counter == 10 {
        break counter * 2;
    }
};
assert_eq!(result, 20);
  • while:条件循环,和 Swift 以及其他许多言语的 while 运用无二致,就不示例了。

  • forin:和 Swift 相同,支撑区间和迭代的运用

// Rust
for i in 0..5 {
    println!("{}", i);
}
// Swift
for i in 0..<5 {
    print("{}", i);
}

搬迁难点

  • 了解并习气作为一门现代言语,Rust 仍保留; 作为分隔符的规划初衷,即「全部皆表达式」,这是 Rust 在操控流方面和 Swift 最大的区别与思想转化点。

形式匹配(Pattern Match)

Rust 和 Swift 相同,支撑强壮的形式匹配,Swift 沿用了 C 风格的 switch 要害字,Rust 是直截了当选用了 match 要害字;以及均支撑 if let 进行更精简的形式匹配处理(了解的配方,Rust 向 Swift 取的经

  • 惯例针对枚举的匹配
// Rust
#[derive(Debug)]
pub enum State {
    Running,
    Stopped,
    Sleeping,
}
fn do_something_based_on_state(curr_state: State, pid: u32) {
    match curr_state {
        State::Running => stop_running_process(pid),
        State::Stopped => restart_stopped_process(pid),
        State::Sleeping => wake_sleeping_process(pid),
    }
}
  • 更丰富的匹配表达
// Rust
let x = 10;
match x {
    1 | 2 | 3 => println!("number is 1 or 2 or 3"),
    4..=10 => println!("number is between 4 and 10 inclusive"),
    x if x * x < 250 => println!("number squared is less than 250"),
    _ => println!("number didn't meet any previous condition!"),
}
// Swift
let x = 10;
switch x {
case 1, 2, 3: print("number is 1 or 2 or 3")
case 4...10: print("number is between 4 and 10 inclusive")
case x where x * x < 250: print("number squared is less than 250")
default: print("number didn't meet any previous condition!")
}
  • if let 风格的精简形式匹配
// Rust
let curr_state = State::Running;
if let State::Running = curr_state {
    println!("Process is running!");
}

函数

搬迁难度:⭐️

Rust 和 Swift 的函数风格非常相似,差异点是:

  • Rust 不支撑默许参数,须选用显式 Option 的办法;

  • Rust 不支撑针对函数内/外部,对参数进行差异化命名;

  • Rust 的参数除非经过 &&mut 显式声明,不然默许为「所有权搬运」语义

    • CoW(Copy on Write)语义经过 Copy trait 标示支撑
  • 以及(再一次),要点了解与习气「全部皆表达式」的思想

// Rust
fn print_labeled_measurement(value: i32, unit_label: char) {
    println!("The measurement is: {}{}", value, unit_label);
}
print_labeled_measurement(5, 'h');
// Swift
func printLabeledMeasurement(value: Int32, unitLabel: String) {
    print("The measurement is: {}{}", value, unitLabel);
}
printLabeledMeasurement(value: 5, unitLabel: "h")

面向目标

封装

搬迁难度:⭐️

和 Swift 一直在尝试引荐运用值语义如出一辙,不过 Rust 更急进,仅支撑经过struct 和 enum 对数据进行封装,彻底抛弃 class 的概念。参阅:「结构体」 & 「枚举」相关小节

承继&多态

搬迁难度:⭐️⭐️

Rust** 不支撑承继**。经过trait(特性,即 Swift 中 protocol)界说同享行为来复用代码,以及完成多态。选用 Swift 了解了面向协议的思想办法,就能够很快习气。

除此之外,和 Swift 相同,会运用泛型进行代码复用,后边会一节专门介绍。

  • 界说一个特性(trait)
// Rust
pub trait Summary {
    fn summarize(&self) -> String;
}
// 支撑默许完成
pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}
  • 为不同类型完成对应的特性
// Rust
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}
impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}
pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}
impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}
  • trait 作为多态参数
// Rust
pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}
  • trait 作为多态返回值
// Rust
fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("horse_ebooks"),
        content: String::from(
            "of course, as you probably already know, people",
        ),
        reply: false,
        retweet: false,
    }
}

搬迁难点与思想转化技巧

  • Rust 的 trait 和 Swift 的 protocol 理念非常相似,可优先经过 Swift 把握面向协议编程的一些根本概念

  • 参阅资料:Swift 中的面向协议编程

拜访操控

搬迁难度:⭐️

Rust 中默许拜访权限是模块内(mod)可见,经过pub 要害字对外开放拜访权限,能够经过“传参”进行更精密的范围操控。

pub | pub ( crate ) | pub ( self ) | pub ( super ) | pub ( in SimplePath )

pub mod outer_mod {
    pub mod inner_mod {
        // This function is visible within `outer_mod`
        pub(in crate::outer_mod) fn outer_mod_visible_fn() {}
        // Same as above, this is only valid in the 2015 edition.
        pub(in outer_mod) fn outer_mod_visible_fn_2015() {}
        // This function is visible to the entire crate
        pub(crate) fn crate_visible_fn() {}
        // This function is visible within `outer_mod`
        pub(super) fn super_mod_visible_fn() {
            // This function is visible since we're in the same `mod`
            inner_mod_visible_fn();
        }
        // This function is visible only within `inner_mod`,
        // which is the same as leaving it private.
        pub(self) fn inner_mod_visible_fn() {}
    }
    pub fn foo() {
        inner_mod::outer_mod_visible_fn();
        inner_mod::crate_visible_fn();
        inner_mod::super_mod_visible_fn();
        // This function is no longer visible since we're outside of `inner_mod`
        // Error! `inner_mod_visible_fn` is private
        //inner_mod::inner_mod_visible_fn();
    }
}

内存办理

引证计数 v.s 所有权机制

搬迁难度:

Swift 经过 ARC(主动引证计数)办理内存,Rust 经过所有权机制办理内存。

引证计数(Reference Count)

  • 经过盯梢和计算类的实例被多少属性,常量和变量所引证,来办理实例内存

  • 保证引证计数>0时,目标不被开释;引证计数=0时,开释目标

  • 注: 只运用于类的实例。结构体和枚举是值类型,不是引证类型,没有经过引证存储和传递;

所有权规矩(Ownership)

  • 一个值只有一个所有者(owner)

  • 所有权(ownership)能够传递(move)给函数和其他变量

  • 所有者担任从内存中删去数据(一旦所有者超出的效果域,则开释内存)

  • 所有者能够对数据进行任何操作并能够对其进行修改

// Rust
{
    let s = String::from("hello"); // s is valid from this point forward
    // do stuff with s
}                                  // 一旦超出效果域,内存开释
                                   // 不行再拜访
// Swift
do {
    let s = String("hello")
    // do stuff with s
}                            // 一旦超出效果域名,内存开释
                             // 不行再拜访

搬迁难点与思想转化技巧

  • 引证计数仅运用于类(class)的实例目标,除此之外,针对 Swift 中的值语义类型(结构体与枚举),便是完成了 Copy 特性的所有权机制

  • 要点需求了解的是所有权可搬运(move):

    • 函数参数调用;
    • 变量重新绑定;
  • 若真实不好了解,能够简略粗犷地视为「引证计数只能为1」,一个目标只能有仅有的变量绑定,除非&借用,不然不行同享拜访。(Copy 语义,不再是同享拜访)

怎么处理所有权被搬运的状况([E0382])

  • 显式调用 .clone() 进行克隆,对内存进行拷贝传递
#[derive(Debug, Clone)]
struct Dot {
    id: String,
    x: i32,
    y: i32
}
fn main() {
    let dot = Dot { id: "dot_1".to_string(), x: 1, y: 2 }; 
    pacman(dot.clone());
    // 再次调用,编译经过 ✅
    pacman(dot);
}
fn pacman(dot: Dot) { 
    println!("Eating {:?}", dot);
}
  • 对数据类型完成 Copy trait,表明该类型能够简略经过位复制发明副本

    • 完成了 Copy trait 的数据类型,将默许经过「值拷贝」语义进行参数传递
#[derive(Debug, Clone, Copy)]
struct Dot {
    id: String,
    x: i32,
    y: i32
}
fn main() {
    let dot = Dot { id: "dot_1".to_string(), x: 1, y: 2 }; 
    pacman(dot); // 完成了 Copy trait,默许经过「值拷贝」传递
    // 再次调用,编译经过 ✅
    pacman(dot);
}
fn pacman(dot: Dot) { 
    println!("Eating {:?}", dot);
}
  • 经过&借用(Borrow),在防止所有权搬运的状况下共用数据

可选型(Optional)

搬迁难度:

Rust 和 Swift 相同支撑可选型,以便更高雅从容地表达和处理「空」的状况。

  • 规范库界说与完成
// Rust
enum Option<T> {
    None,
    Some(T),
}
// Swift
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
    public init(nilLiteral: ()) {
        self = .none
    }
}
  • 惯例运用
// Rust
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
// Swift
let some_number = Optional(5)
let some_string = Optional("a string")
let absent_number: Int32? = .none
// 更 Swifty 的办法
let someNumber: Int? = 5
let someString: String? = "a string"
let absentNumber: Int32? = nil

搬迁难点

  • Rust 中的可选型和 Swift 比较,是去?/!语法糖版别,没有 Swift 那么便利,刚开始会不太习气

智能指针

搬迁难度:

Box

Box<T>是最简略的引证语义的封装,在堆上分配内存后的引证指针,且仅支撑有一个所有者(owner,相似 Swift 中的强引证)。

// Rust
let a = Box::new(5);
let b = a; // a 被`move`到了 b
// 报错:use of moved value: `a`
println!("{:?}", a);

Rc(refence-counting)

比较 Box,Rc<T> 略微更像 Swift 中的引证些了,经过「浅拷贝」支撑多个引证了。

// Rust
use std::rc::Rc;
let a = Rc::new([5]);
let b = a.clone(); // 相当于 Swift 中的浅拷贝
println!("{:?}", a); // 打印:[5]

Arc(Atomically Reference Counted)

Arc<T> 直译一下的话,感觉有点了解,「原子引证计数」,但不要将它和 Swift 中内存办理办法混淆。Arc 和 Rc 的效果差不多,但 Rc 是在单线程下运用,Arc 是在多线程下运用,因而 clone 的完成是原子性的,因而能做到线程安全。

// Rust
use std::sync::Arc;
let foo = Arc::new(vec![1.0, 2.0, 3.0]);
let a = foo.clone();

Arc 是只读引证,要运用可写引证,需求再另外运用 Mutex 来完成,相似Arc<Mutex<T>>。

搬迁难点与技巧

  • 由于 Rust 对内存的办理机制基于所有权规矩,因而根本彻底做到了默许运用更高效的「栈内存」,所以要拓荒「堆内存」并运用引证语义,则需求凭借智能指针。

  • 能够将智能指针了解为对必须运用class(引证语义)的场景弥补

  • 不过,从客户端的视角,针对上层业务开发,运用到智能指针的频率较低,渐渐了解也没关系

结语

耐心看到这的你,开始 happy coding 吧,相信你会同时爱上 Swift & Rust 的。

  • ️ rustup gogo:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

参阅

  • Announcing Rust 1.0
  • Swfit 2.0
  • The Rust Programming Language – The Rust Programming Language
  • From Swift To C++
  • Rust – 棒棒彬的第二大脑
  • ~gruberb/onetutorial – sourcehut git