Intro
Rust에서 제공하는 Data Type 여러 가지가 있지만 기본적으로 제공하는 Type은 크게 Primary Type과 Advenced Type, Compound Type, Collection Type으로 나눌 수 있습니다.
- Primary Type : 정수, 소수, 문자(char), 참/거짓,
- Advenced Type : 문자열(&str, String)
- Component Type : Tuple, Array, Slice, ...
- Collection Type : Vector, Map, Set, ...
- Custom Type : Enum, Struct, ...
예제를 통해 어떻게 사용할 수 있는지 확인해 보겠습니다.
Code Example
Rust 1.79.0 (released 2024-06-13)
fn main(){
// =============================================
// Primary type
// =============================================
/* integer type */
let _i: i8 = 0;
let _i: i16 = 1_000; // underscore 사용 가능
let _i: i32 = 32; // 정수 기본 추론 type
let _i: i64 = 0xff; // 16진법, 8진법 등 다양한 기술을 지원.
let _i: i128 = i128::MIN; // Type 자체에서 가져와서 사용할 수 있다.
let _i: isize = 0; // os의 메모리 주소크기를 따름.
/* unsigned integer type */
let _u: u8 = b'a'; // char와 호환된다. Vec<u8>이 String과 같음을 기억하자.
let _u: u16 = 0;
let _u: u32 = 0;
let _u: u64 = 0xFFFF_FFFF_FFFF_FFFF; // u64::MAX와 같은표현.
let _u: u128 = u128::MAX; // integer중 중 가장 큰 수;
let _u: usize = 0; // os의 메모리 주소크기를 따름.
// 64bit OS에서는 64bit 메모리 주소를 가지므로 usize = u64
/* float type */
let _f: f32 = 0.0;
let _f: f64 = 0.0; // 실수 기본 추론 Type
// let _f: f16 = 0.0; // [ERROR] 지원하는 HW에서만 사용 가능
// let _f: f128 = 0.0; // [ERROR] 지원하는 HW에서만 사용 가능. (예: PowerPC)
/* boolean type */
let _b: bool = true;
let _b: bool = false;
let _c: char = 'c'; // ''는 한 글자 ascii에서 사용
/* casting */
let _num_int: i32 = 5/3; // type이 동일해야 산술 연산 가능
let _num_float: f64 = 5.0/3.0; // type이 동일해야 산술 연산 가능
// [Error] rust는 자동 형변환이 일어나지 않는다
// let _num_div = 5/3.0;
let _num_int: i32 = 5 / 3.0 as i32; // as라는 keyword로 명시적인 casting을 지원.
// =============================================
// Advenced Type
// =============================================
/* &str Type */
// &str : pointer, length(문자 수)를 가지는 immutable한 data.
// String : pointer, length(문자 수), capacity(Memory 크기)를 가지는 mutable한 data.
// &str은 주로 수정되지 않는 글자열을 다루는 String Slice. rust는 utf-8을 기본으로 한다.
let _str: &str = "str";
// 불가능한 문법은 아니지만 mutable한 속성을 이용하기 어렵다.
// let mut _str = "test";
/* String Type */
// String은 Vec<u8> 형태의 객체 Type. 주로 수정될 것을 목적으로 한 문자열.
let _string: String = String::from("string");
// String 선언 방법 1.
let _string = String::from("string");
// String 선언 방법 2. 사실상 &str -> String 변환이다.
let _string = "string".to_string();
// String은 mutable하게 선언할 수 있다.
let mut _string_mutable = String::from("mutable");
_string_mutable.push_str(" add text");
println!("_string_mutable : {_string_mutable}"); // mutable add text
// String은 mutable하지만 mut를 선언한 변수만 변경 가능하다.
let _string_immutable = String::from("immutable");
// _string_immutable.push_str("test"); // [Error]
// =============================================
// Compound Types
// =============================================
/* Tuple type */
// 길이와 type들이 고정된 단위 Data type
let _t: (i32, f64, &str) = (1, 2.34, "567 number");
// tuple에서 값을 분리해서 받을 수 있다.
let (_t1, _t2, _t3) = _t;
let mut _t_mut: (i32, i32) = (1, 2); // mutable 선언
_t_mut.0 = 3; // Tuple indexing
_t_mut.1 = 4; // Tuple indexing
// Compound Type을 print할 때는 {:?}, {:#?}같은 문법을 사용한다.
println!("_t_mut : {_t_mut:?}");
// [ERROR] rust는 tuple의 indexing을 variable로 할 수 없다.
// const ADDRESS: usize = 1;
// _t_mut.ADDRESS = -4;
/* Array type */
let _a: [i32; 5] = [1, 2, 3, 4, 5];
let _a = [1, 2, 3, 4, 5]; // type 생략해도 됨.
println!("_a[0] : {}", _a[0]); // Array indexing
let address: usize = 3;
println!("array : {_a:?}");
// const를 활용한 변수 indexing은 가능하다. out of bound를 compiler time에 검사 가능
println!("_a[address] : {}", _a[address]);
let _a_repeat: [i32; 10] = [1; 10]; // rust의 array 반복 숫자 선언 방법
println!("_a_repeat : {_a_repeat:?}"); // [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// [TIP] 1 ~ 10까지의 값을 뽑을 수 있음.
let _a_increment:[usize; 10] = core::array::from_fn(|i| i + 1);
println!("_a_increment : {_a_increment:?}"); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 다양한 차원에 대해서 선언할 수 있다. 3 x 4 x 5로 이루어진 3차원의 1로 채워진 데이터.
let mut _arr3d = [
[
[1; 3]; 4
]; 5
];
/*
[
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
]
*/
println!("array : {_arr3d:?}");
println!("array element : {}", _arr3d[4][3][2]); // 다차원 array의 index 접근
_arr3d[0] = [[2; 3]; 4]; // 다차원 array insert
println!("array : {_arr3d:?}");
/*
[
[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
]
*/
/* Slice */
let arr: [i32; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
let slice: &[i32] = &arr[2..5];
println!("slice : {slice:?}"); // [2, 3, 4]
// =============================================
// Collection Types
// =============================================
use std::collections::{HashMap, HashSet, BTreeMap, BTreeSet};
/* Vector : 동적 크기 배열, runtime에 크기를 조정할 수 있음 */
let mut _v:Vec<i32> = Vec::new(); // 가변 길이의 데이터 저장 Type인 빈 Vector 선언
let mut v = Vec::new(); // push할 데이터 기반 Type 추론
v.push(1);
v.push(2);
v.push(3);
v.push(4);
println!("{v:?}");
// 가변 길이의 데이터 저장 Type인 빈 Vector 선언(macro version)
let mut _v:Vec<i32> = vec![];
// 가변 길이의 데이터 저장 Type인 데이터 포함 Vector 선언(macro version)
let mut _v:Vec<i32> = vec![1, 2, 3, 4];
/* HashMap : 중복되지 않는 key와 value pairs로 데이터를 저장하는 구조, unordered */
let mut _h_map: HashMap<&str, i32> = HashMap::new(); // 순서 없는 key, value 기반 data type
let mut h_map = HashMap::new(); // push할 데이터 기반 Type 추론
// insert
h_map.insert("key1", 1);
h_map.insert("key2", 2);
h_map.insert("key3", 3);
// overwrite
h_map.insert("key1", 11); // 중복된 키 "key1"에 삽입 -> overwrite
// get
h_map.get("no_key"); // None
h_map.get("key2"); // Some(2)
// update
// key가 없으면 update 동작을 하지 않는다.
if let Some(value) = h_map.get_mut("no_key") { *value += 10; }
// key가 있다면 value를 받아와 update한다.
if let Some(value) = h_map.get_mut("key3") { *value *= 10; } // 30
// remove. pop처럼 꺼내면서 값을 출력한다.
println!("key2 : {:?}", h_map.remove("key2")); // pop과 같은 동작. Some(2)
println!("key2 : {:?}", h_map.remove("key2")); // 없는 key에 pop을 하면 None을 얻는다.
// check key
println!("key 1 contained : {}", h_map.contains_key("key1"));
println!("no key contained : {}", h_map.contains_key("no_key"));
// size
println!("Number of elements: {}", h_map.len());
// clear (모든 키, 값 삭제)
h_map.clear();
println!("Number of elements after clear: {}", h_map.len()); // 0
/* Hashset : 중복되지 않는 값을 저장하는 구조. unordered */
let mut _h_set: HashSet<&str> = HashSet::new(); // 순서 없는 값 기반 data type
let mut h_set = HashSet::new(); // push할 데이터 기반 Type 추론
// insert
h_set.insert("apple");
h_set.insert("banana");
h_set.insert("cherry");
// 중복된 값 추가 시 삽입되지 않음
h_set.insert("apple"); // "apple"은 이미 존재하므로 삽입되지 않음
// contains (값이 존재하는지 확인)
println!("Contains 'banana': {}", h_set.contains("banana")); // true
println!("Contains 'grape': {}", h_set.contains("grape")); // false
// remove. 값이 있었다면 true, 없었다면 false
println!("cherry : {}", h_set.remove("cherry")); // true, 값이 삭제됨
println!("cherry : {}", h_set.remove("cherry")); // false, 값이 존재하지 않음
// size
println!("Number of elements: {}", h_set.len()); // 2 ("apple", "banana")
// clear (모든 값 삭제)
h_set.clear();
println!("Number of elements after clear: {}", h_set.len()); // 0
// Iterating through HashSet
h_set.insert("one");
h_set.insert("two");
h_set.insert("three");
for value in &h_set {
println!("{}", value); // "one", "two", "three" (순서 없음)
}
/* BtreeMap : HashMap에서 Key, Value를 순서대로 정렬된 상태를 유지하는 data 구조 */
let mut btree_map = BTreeMap::new();
btree_map.insert(3, "three");
btree_map.insert(1, "one");
btree_map.insert(2, "two");
// 순서대로 키-값 출력
for (key, value) in &btree_map {
println!("{}: {}", key, value);
}
// 첫 번째, 마지막 값
if let Some((key, value)) = btree_map.iter().next() {
println!("First: {}: {}", key, value);
}
if let Some((key, value)) = btree_map.iter().rev().next() {
println!("Last: {}: {}", key, value);
}
/* BtreeSet : HashSet에서 Value를 순서대로 정렬된 상태를 유지하는 data 구조 */
// BTreeSet 예시
let mut btree_set = BTreeSet::new();
btree_set.insert(3);
btree_set.insert(1);
btree_set.insert(2);
// 순서대로 값 출력
for value in &btree_set {
println!("{}", value);
}
// 첫 번째, 마지막 값
if let Some(first) = btree_set.iter().next() {
println!("First: {}", first);
}
if let Some(last) = btree_set.iter().rev().next() {
println!("Last: {}", last);
}
// 범위 출력
let range: Vec<_> = btree_set.range(1..3).collect();
println!("Range (1..3): {:?}", range);
// =============================================
// Custom Types
// =============================================
/* Struct type : type들의 집합. field에 이름이 있음 */
struct _Point {
x: i32,
y: i32,
}
let _point = _Point {x: 10, y: 10};
// [Error] error[E0277]: `_Point` doesn't implement `Debug`
// println!("point : {point:?}"); // struct는 그냥 print할 수 없다.
println!("(x, y) : ({}, {})", _point.x, _point.y);
// struct를 print하려면 Debug trait을 적용해야 한다.
#[derive(Debug)]
struct Point {
x: i32,
y: i32
}
let point = Point {x: 10, y: 10};
println!("point : {point:?}");
println!("(x, y) : ({}, {})", point.x, point.y);
/* Enum : 열거형. 값은 u8기준으로 0부터 들어간다. 임의로 넣을 수 있으며 다른 정수 type도 가능하다. */
#[derive(Debug)]
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right=30, // value도 따로 넣을 수 있다.
// double=true, // [Error] boolean type은 안된다. 정수형만 허용
}
let up = Direction::Up;
let down = Direction::Down;
let left = Direction::Left;
let right = Direction::Right;
println!("{up:?}, {down:?}, {left:?}, {right:?}"); // Up, Down, Left, Right
// 값을 출력하고 싶다면 casting을 사용하면 된다.
println!("up value : {}", up as u8); // up value : 0
println!("right value : {}", right as u8); // right value : 30
}
* reference
- https://doc.rust-lang.org/book/
'Rust > Basic' 카테고리의 다른 글
[Rust Tutorial] 6 - Control Flow (0) | 2024.11.17 |
---|---|
[Rust Tutorial] 5 - Function (0) | 2024.11.17 |
[Rust Tutorial] 3 - Variables (0) | 2024.11.14 |
[Rust Tutorial] 2 - Cargo 사용법 (0) | 2024.11.14 |
[Rust Tutorial] 1 - Introduce (0) | 2024.11.13 |