首页 > 解决方案 > Rust 中双引号和单引号的区别

问题描述

我在 Rust 中进行 2020 年第 3 天的adventofcode 进行一些训练,因为我是 Rust 新手,而且我的代码无法编译,具体取决于我在“树”变量上使用单引号还是双引号

第一个代码片段不会编译并抛出错误:预期u8,找到&[u8; 1]

use std::fs;

fn main() {
    let text: String = fs::read_to_string("./data/text").unwrap();
    let vec: Vec<&str> = text.lines().collect();
    let vec_vertical_len = vec.len();
    let vec_horizontal_len = vec[0].len();

    let mut i_pointer: usize = 0;
    let mut j_pointer: usize = 0;
    let mut tree_counter: usize = 0;

    let tree = b"#";
    loop {
        i_pointer += 3;
        j_pointer += 1;
        if j_pointer >= vec_vertical_len {
            break;
        }

        let i_index = i_pointer % vec_horizontal_len;
        let character = vec[j_pointer].as_bytes()[i_index];
        if character == tree {
           tree_counter += 1
        }
    }

    println!("{}", tree_counter);
}

第二个片段编译并给出正确的答案..

use std::fs;

fn main() {
    let text: String = fs::read_to_string("./data/text").unwrap();
    let vec: Vec<&str> = text.lines().collect();
    let vec_vertical_len = vec.len();
    let vec_horizontal_len = vec[0].len();

    let mut i_pointer: usize = 0;
    let mut j_pointer: usize = 0;
    let mut tree_counter: usize = 0;

    let tree = b'#';
    loop {
        i_pointer += 3;
        j_pointer += 1;
        if j_pointer >= vec_vertical_len {
            break;
        }

        let i_index = i_pointer % vec_horizontal_len;
        let character = vec[j_pointer].as_bytes()[i_index];
        if character == tree {
           tree_counter += 1
        }
    }

    println!("{}", tree_counter);
}

我没有找到任何参考来解释使用单引号或双引号时发生了什么……有人可以帮助我吗?

标签: rust

解决方案


简短的回答是它的工作方式类似于 java。字符的单引号和字符串的双引号。

let a: char = 'k';
let b: &'static str = "k";

b''or前缀意味着取我在这里的b""内容并解释为字节文字。

let a: u8 = b'k';
let b: &'static [u8; 1] = b"k";

字符串导致引用的原因是它们在编译后的二进制文件中的存储方式。在每个方法中存储一个字符串常量效率太低了,所以字符串被放在标题区域的二进制文件的开头。当您的程序正在执行时,您将引用该标头中的字节(因此是静态生命周期)。

进一步深入兔子洞,单引号在技术上包含一个代码点。这基本上就是你可能认为的角色。因此,Unicode 字符也将被视为单个代码点,即使它可能是多个字节长。假定代码点适合 au32或更少,因此您可以char使用安全地转换任何代码点as u32,但不能反过来,因为并非所有u32值都匹配有效代码点。这也意味着b'\u{x}'无效,因为\u{x}可能会产生不适合单个字节的字符。

// U+1F600 is a unicode smiley face
let a: char = '\u{1F600}';
assert_eq!(a as u32, 0x1F600);

但是,您可能会发现有趣的是,由于 Rust 字符串存储为 UTF-8,超过 127 的代码点将占用字符串中的多个字节,尽管它们自己适合单个字节。您可能已经知道,UTF-8 只是一种将代码点转换为字节并再次转换回来的方法。

let foo: &'static str = "\u{1F600}";
let foo_chars: Vec<char> = foo.chars().collect();
let foo_bytes: Vec<u8> = foo.bytes().collect();
    
assert_eq!(foo_chars.len(), 1);
assert_eq!(foo_bytes.len(), 4);

assert_eq!(foo_chars[0] as u32, 0x1F600);
assert_eq!(foo_bytes, vec![240, 159, 152, 128]);

推荐阅读