7.20. Rust collections and strings

发布时间 :2023-11-09 23:00:09 UTC      

Collection is the most common form of data storage in data structures. Rust standard library provides a wealth of collection types to help developers deal with the operation of data structures.

7.20.1. Vector #

Vector is a single data structure that stores multiple values, which stores values of the same type in memory linearly.

The vector is a linear table and is represented as Vec < T > in Rust.

Vectors are used in a way similar to lists (List), in which we can create vectors of a specified type:

let vector: Vec<i32> = Vec::new(); // Create an empty vector of type i32
let vector = vec![1, 2, 4, 8];     // Creating vectors through arrays

We often use append operations when we use linear tables, but append and stack push the operation is essentially the same, so the vector is only``push`` method to append a single element:

Example #

fn main() {
    let mut vector = vec![1, 2, 4, 8];
    vector.push(16);
    vector.push(32);
    vector.push(64);
    println!("{:?}", vector);
}

Running result:

[1, 2, 4, 8, 16, 32, 64]

append method is used to splice one vector to the tail of another:

Example #

fn main() {
    let mut v1: Vec<i32> = vec![1, 2, 4, 8];
    let mut v2: Vec<i32> = vec![16, 32, 64];
    v1.append(&mut v2);
    println!("{:?}", v1);
}

Running result:

[1, 2, 4, 8, 16, 32, 64]

get method is used to extract the value from the vector:

Example #

fn main() {
    let mut v = vec![1, 2, 4, 8];
    println!("{}", match v.get(0) {
        Some(value) => value.to_string(),
        None => "None".to_string()
    });
}

Running result:

1

Because the length of the vector cannot be logically inferred, and the get method cannot guarantee a certain value, so get the return value of the method is Option enumerated class, may be empty.

This is a safe way to get a value, but it is a bit troublesome to write. If you can guarantee that the subscript of the value will not exceed the range of the vector subscript, you can also use the array value syntax:

Example #

fn main() {
    let v = vec![1, 2, 4, 8];
    println!("{}", v[1]);
}

Running result:

2

But if we try to get v[4] , then the vector returns an error

Ergodic vector:

Example #

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
            println!("{}", i);
    }
}

Running result:

100
32
57

If you need to change the value of a variable during traversal:

Example #

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
}

7.20.2. String #

String classes have been used a lot so far in this chapter, so there are many methods that readers are familiar with. This chapter mainly introduces the method of string and UTF-8 nature.

Create a new string:

let string = String::new();

Convert the underlying type to a string:

let one = 1.to_string();         // Integer to string
let float = 1.3.to_string();     // Floating point number to string
let slice = "slice".to_string(); // String Slice to String

Include UTF-8 string of characters:

let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("hello");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");

Append string:

let mut s = String::from("run");
s.push_str("oob"); // Append String Slice
s.push('!');       // Append characters

Concatenate strings with a + sign:

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;

This syntax can also contain string slices:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");

let s = s1 + "-" + &s2 + "-" + &s3;

Use format! macros:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");

let s = format!("{}-{}-{}", s1, s2, s3);

String length:

let s = "hello";
let len = s.len();

Here the value of len is 5.

let s = "hello";
let len = s.len();

Here len value is 6. Because Chinese is UTF-8 encoded, each character is 3 bytes long, so the length is 6. But it is supported in Rust UTF-8 character object, so if you want to count the number of characters, you can first take the string as a character collection:

let s = "hello";
let len = s.chars().count();

Here len is 7 because there are 7 characters in one The speed of statistical characters is much slower than the length of statistical data.

Traversal string:

Example #

fn main() {
    let s = String::from("hello(Chinese)");
    for c in s.chars() {
        println!("{}", c);
    }
}

Running result:

h
e
l
l
o
Chinese

Take a single character from a string:

Example #

fn main() {
    let s = String::from("EN Chinese");
    let a = s.chars().nth(2);
    println!("{:?}", a);
}

Running result:

Some

Note: nth function is a way to extract a value from an iterator, so please don’t use it like this in traversal! Because UTF-8 the length ofeach character is not necessarily equal!

To intercept a string string:

Example #

fn main() {
    let s = String::from("EN Chinese");
    let sub = &s[0..2];
    println!("{}", sub);
}

Running result:

EN

But please note that it is possible to dismember a UTF-8 characters! That would lead to an error:

Example #

fn main() {
    let s = String::from("EN Chinese");
    let sub = &s[0..3];
    println!("{}", sub);
}

Running result:

thread 'main' panicked at 'byte index 3 is not a char boundary; it is inside (bytes 2..5) of `EN Chinese`', src\libcore\str\mod.rs:2069:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

7.20.3. Mapping table #

Mapping tables exist widely in other languages. Among them, the most common application is key hash mapping table (Hash Map).

Create a new hash value mapping table:

Example #

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", "10 m^2");
    println!("{}", map.get("color").unwrap());
}

Note: generics for hash tables are not declared here because of Rust’s automatic type determination mechanism.

Running result:

red

insert Methods and get method is the two most commonly used methodsfor mapping tables.

The mapping table supports iterators:

Example #

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", "10 m^2");
    for p in map.iter() {
        println!("{:?}", p);
    }
}

Running result:

("color", "red")
("size", "10 m^2")

Iteration elements are tuples that represent key-value pairs.

Rust’s mapping table is a very convenient data structure when using the insert method to add a new key-value pair, if the same key already exists, the corresponding value is directly overwritten. If you want to “insert safely”, that is, the insert action is performed only when you confirm that a key does not currently exist, you can do this:

map.entry("color").or_insert("red");

This sentence means that if there is no key for "color" , add it and set the value to "red" otherwise, it will be skipped

If you want to change the corresponding value directly if you have determined that there is a key, there is a faster way:

Example #

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert(1, "a");

    if let Some(x) = map.get_mut(&1) {
        *x = "b";
    }
}

Principles, Technologies, and Methods of Geographic Information Systems  102

In recent years, Geographic Information Systems (GIS) have undergone rapid development in both theoretical and practical dimensions. GIS has been widely applied for modeling and decision-making support across various fields such as urban management, regional planning, and environmental remediation, establishing geographic information as a vital component of the information era. The introduction of the “Digital Earth” concept has further accelerated the advancement of GIS, which serves as its technical foundation. Concurrently, scholars have been dedicated to theoretical research in areas like spatial cognition, spatial data uncertainty, and the formalization of spatial relationships. This reflects the dual nature of GIS as both an applied technology and an academic discipline, with the two aspects forming a mutually reinforcing cycle of progress.