Rust 练习册 21:Hello World 与入门基础

在学习任何编程语言时,"Hello, World!" 程序都是我们的第一个里程碑。它不仅验证了开发环境的正确配置,也为我们打开了探索新语言特性的大门。在 Exercism 的 "hello-world" 练习中,我们将通过这个简单的程序了解 Rust 的基本语法、测试驱动开发(TDD)流程以及语言的核心概念。

什么是 Hello World?

"Hello, World!" 程序是每个程序员学习新语言时编写的第一个程序。它的目标很简单:在屏幕上输出 "Hello, World!" 这个字符串。虽然看似简单,但它涉及了编程语言的多个基本概念:

  1. 函数定义
  2. 返回值
  3. 字符串处理
  4. 程序入口点

在 Rust 中,这个程序帮助我们理解模块系统、生命周期、静态字符串等核心概念。

练习结构分析

让我们先看看练习提供的文件结构和代码:

复制代码
hello-world/
├── src/
│   └── lib.rs
├── tests/
│   └── hello-world.rs
├── Cargo.toml
└── GETTING_STARTED.md

主要代码文件

rust 复制代码
// The &'static here means the return type has a static lifetime.
// This is a Rust feature that you don't need to worry about now.
pub fn hello() -> &'static str {
    "Hello world!"
}
rust 复制代码
#[test]
fn test_hello_world() {
    assert_eq!("Hello, World!", hello_world::hello());
}
toml 复制代码
[package]
edition = "2018"
name = "hello-world"
version = "1.1.0"

设计分析

1. 函数签名解析

rust 复制代码
pub fn hello() -> &'static str {
    "Hello world!"
}

让我们逐行分析这个函数:

  1. pub - 表示这是一个公共函数,可以从其他模块访问
  2. fn hello() - 定义一个名为 hello 的函数,不接受任何参数
  3. -> &'static str - 函数返回类型,表示返回一个具有静态生命周期的字符串切片
  4. "Hello world!" - 返回一个字符串字面量

2. 测试代码解析

rust 复制代码
#[test]
fn test_hello_world() {
    assert_eq!("Hello, World!", hello_world::hello());
}

测试代码使用了 Rust 的内置测试框架:

  1. #[test] - 属性标记,表明这是一个测试函数
  2. assert_eq! - 宏,用于断言两个值相等
  3. hello_world::hello() - 调用我们实现的 hello 函数

3. Cargo 配置

toml 复制代码
[package]
edition = "2018"
name = "hello-world"
version = "1.1.0"

Cargo.toml 文件定义了包的基本信息:

  • edition: 使用的 Rust 版本(2018 edition)
  • name: 包名称
  • version: 版本号

完整实现

1. 修正版本

通过运行测试,我们发现需要将返回值从 "Hello world!" 修改为 "Hello, World!":

rust 复制代码
// The &'static here means the return type has a static lifetime.
// This is a Rust feature that you don't need to worry about now.
pub fn hello() -> &'static str {
    "Hello, World!"
}

2. 扩展版本

我们可以扩展这个函数以支持更多功能:

rust 复制代码
// 基础版本
pub fn hello() -> &'static str {
    "Hello, World!"
}

// 支持自定义姓名的版本
pub fn hello_with_name(name: &str) -> String {
    if name.is_empty() {
        "Hello, World!".to_string()
    } else {
        format!("Hello, {}!", name)
    }
}

// 支持多种语言的版本
pub fn hello_multilingual(language: &str) -> &'static str {
    match language.to_lowercase().as_str() {
        "english" => "Hello, World!",
        "spanish" => "¡Hola, Mundo!",
        "french" => "Bonjour, le Monde!",
        "german" => "Hallo, Welt!",
        "chinese" => "你好,世界!",
        _ => "Hello, World!",
    }
}

测试驱动开发(TDD)流程

1. 运行初始测试

sh 复制代码
$ cargo test

测试失败输出:

复制代码
running 1 test
test test_hello_world ... FAILED

failures:

---- test_hello_world stdout ----
thread 'test_hello_world' panicked at 'assertion failed: `(left == right)`
(left: `"Hello, World!"`, right: `"Hello world!"`)', tests/hello-world.rs:5

2. 理解测试失败

测试期望得到 "Hello, World!",但我们返回的是 "Hello world!"(缺少逗号)。

3. 修复代码

修改 src/lib.rs 文件:

rust 复制代码
pub fn hello() -> &'static str {
    "Hello, World!"
}

4. 重新运行测试

sh 复制代码
$ cargo test

测试通过输出:

复制代码
running 1 test
test test_hello_world ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

性能优化版本

对于这样一个简单的函数,性能优化并不必要,但我们可以看看不同的实现方式:

rust 复制代码
// 使用 const 值
const HELLO_WORLD: &str = "Hello, World!";

pub fn hello() -> &'static str {
    HELLO_WORLD
}

// 使用 lazy_static(需要添加依赖)
// [dependencies]
// lazy_static = "1.4"
#[macro_use]
extern crate lazy_static;

lazy_static! {
    static ref HELLO_WORLD: String = "Hello, World!".to_string();
}

pub fn hello_lazy() -> &'static str {
    &HELLO_WORLD
}

// 使用 Box<str>(堆分配)
pub fn hello_boxed() -> Box<str> {
    "Hello, World!".into()
}

错误处理和边界情况

虽然 Hello World 程序很简单,但我们仍可以考虑一些边界情况:

rust 复制代码
#[derive(Debug, PartialEq)]
pub enum HelloWorldError {
    EmptyName,
    InvalidCharacters,
}

pub fn hello_safe(name: Option<&str>) -> Result<&'static str, HelloWorldError> {
    match name {
        None => Ok("Hello, World!"),
        Some("") => Err(HelloWorldError::EmptyName),
        Some(n) if n.chars().all(|c| c.is_alphabetic() || c.is_whitespace()) => {
            Ok("Hello, World!")
        }
        Some(_) => Err(HelloWorldError::InvalidCharacters),
    }
}

扩展功能

基于基础实现,我们可以添加更多功能:

rust 复制代码
pub struct HelloWorldGreeter {
    default_greeting: &'static str,
}

impl HelloWorldGreeter {
    pub fn new() -> Self {
        HelloWorldGreeter {
            default_greeting: "Hello, World!",
        }
    }

    pub fn new_with_greeting(greeting: &'static str) -> Self {
        HelloWorldGreeter {
            default_greeting: greeting,
        }
    }

    pub fn greet(&self) -> &'static str {
        self.default_greeting
    }

    pub fn greet_person(&self, name: &str) -> String {
        if name.is_empty() {
            self.default_greeting.to_string()
        } else {
            format!("Hello, {}!", name)
        }
    }

    pub fn greet_custom(&self, greeting: &str, name: &str) -> String {
        if name.is_empty() {
            greeting.to_string()
        } else {
            format!("{}, {}!", greeting, name)
        }
    }
}

// 便利函数
pub fn hello() -> &'static str {
    HelloWorldGreeter::new().greet()
}

// 支持多语言的版本
pub struct MultilingualGreeter {
    greetings: std::collections::HashMap<String, &'static str>,
}

impl MultilingualGreeter {
    pub fn new() -> Self {
        let mut greetings = std::collections::HashMap::new();
        greetings.insert("english".to_string(), "Hello, World!");
        greetings.insert("spanish".to_string(), "¡Hola, Mundo!");
        greetings.insert("french".to_string(), "Bonjour, le Monde!");
        greetings.insert("german".to_string(), "Hallo, Welt!");
        greetings.insert("chinese".to_string(), "你好,世界!");

        MultilingualGreeter { greetings }
    }

    pub fn greet(&self, language: &str) -> &'static str {
        self.greetings
            .get(&language.to_lowercase())
            .copied()
            .unwrap_or("Hello, World!")
    }
}

实际应用场景

尽管 Hello World 程序看起来很简单,但它在实际开发中有以下应用:

  1. 环境验证:验证开发环境是否正确配置
  2. 示例代码:作为学习新语言的入门示例
  3. API 端点:在 Web 服务中作为健康检查端点
  4. 基准测试:作为性能测试的基线
  5. 教学工具:用于编程教学和演示
  6. 模板项目:作为新项目的起点

算法复杂度分析

  1. 时间复杂度:O(1)

    • 函数直接返回一个预定义的字符串字面量
  2. 空间复杂度:O(1)

    • 字符串字面量存储在程序的只读数据段中

与其他实现方式的比较

rust 复制代码
// 返回 String 而不是 &str
pub fn hello_string() -> String {
    "Hello, World!".to_string()
}

// 使用格式化宏
pub fn hello_formatted() -> String {
    format!("Hello, World!")
}

// 使用 Vec<u8> 和 UTF-8
pub fn hello_bytes() -> String {
    String::from_utf8(vec![72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]).unwrap()
}

// 使用字符数组
pub fn hello_array() -> String {
    let chars = ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'];
    chars.iter().collect()
}

总结

通过 hello-world 练习,我们学到了:

  1. Rust 基础语法:函数定义、返回值、字符串处理
  2. 测试驱动开发:理解 TDD 流程和 cargo test 命令
  3. 模块系统:理解 pub 关键字和模块访问
  4. 生命周期:初步了解 &'static 生命周期
  5. 包管理:熟悉 Cargo.toml 配置文件
  6. 错误处理:学习如何处理测试失败

这些技能是学习 Rust 的基础,虽然 Hello World 程序很简单,但它为我们打开了 Rust 世界的大门。通过这个练习,我们不仅学会了如何编写和测试 Rust 代码,还了解了 Rust 生态系统的基本工具和概念。

这是 Rust 学习之旅的第一步,后续的练习将逐步引入更复杂的概念,如所有权、借用、trait、泛型等。掌握好这些基础知识,将为我们后续的学习打下坚实的基础。

相关推荐
YUJIANYUE1 小时前
查立得PHP+Mysql影院选座式教室座位预定系统 v1.0
开发语言·mysql·php
u***09641 小时前
后端服务熔断降级策略,错误率阈值 什么是服务熔断降级
java·开发语言
绝无仅有1 小时前
大厂面试题MySQL解析:MVCC、Redolog、Undolog与Binlog的区别
后端·面试·架构
烤麻辣烫1 小时前
23种设计模式(新手)-3接口隔离原则
java·开发语言·学习·设计模式·intellij-idea
绝无仅有1 小时前
MySQL面试题解析:MySQL读写分离与主从同步
后端·面试·架构
MegatronKing1 小时前
一个有意思的问题引起了我的反思
前端·后端·测试
JohnYan1 小时前
Bun技术评估 - 30 SSE支持
javascript·后端·bun
程序猿_极客1 小时前
【2025最新】 Java 入门到实战:数组 + 抽象类 + 接口 + 异常(含案例 + 语法全解析+巩固练习题)
java·开发语言·后端·java基础·java入门到实战
yzx9910131 小时前
一个嵌入式存储芯片质量评估系统的网页界面设计
开发语言·javascript·ecmascript