데이터 타입#

Rust의 모든 값은 Data type을 가집니다.
Rust는 정적 타입 언어이기 때문에 컴파일 시점에 Data type이 정해져 있어야 합니다.

1. Scalar type#

Scalar type은 값 하나를 표현하며 다음 4종류의 Scalar type이 있습니다.

1.1 integer#

integer는 정수를 사용하는 type이며 소수점은 사용할 수 없습니다.
integer type의 종류는 다음 표와 같습니다.

SizeSignedUnsigned
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize

여기서, i는 부호 있는(Signed) 정수로 양수와 음수를 사용할 수 있습니다.
u는 부호 없는(Unsigned) 정수로 양수만 사용할 수 있습니다.
Signed는 1-Bit를 부호로 사용하기 때문에 값의 표현 범위가 Unsigned보다 작습니다.
값의 표현 범위는 다음 수식처럼 계산할 수 있으며, $n$은 사용 비트 수를 의미합니다.

  • Signed : $-(2^{n-1})$ 부터 $2^{n-1}-1$ 까지
  • Unsigned : 0 부터 $2^{n}-1$ 까지

예를 들어, i8은 $-(2^{7})=-128$ 부터 $2^{7}-1=127$ 까지의 값을 사용할 수 있고,
u8은 $0$ 부터 $2^{8}-1=255$ 까지의 값을 사용할 수 있습니다.
 
arch는 컴퓨터가 32-bit Architecture이면 32-bit를 사용하고, 64-bit Architecture이면 64-bit를 사용합니다.
 
※ Integer overflow
값의 표현 범위를 넘어가면 다음의 2가지 경우가 발생합니다.

  • Debug mode : Panic 발생하여 프로그램이 종료 됩니다. (예를 들어, u8 변수에 256을 저장하면 Panic 발생합니다.)
  • Release mode : 값 표현 범위의 최소값으로 지정됩니다. (예를 들어, u8 변수에 256을 저장하면 overflow 되어 0이 됩니다.)

1.2 floating-point#

Rust에서 소수점을 가지는 실수를 표현하기 위하여 Floating point type을 사용합니다.
Floating point type은 32-bit 크기를 가지는 f32 와 64-bit 크기를 가지는 f64가 있습니다.

다음 코드처럼 Type을 명시하지 않는 경우 기본적으로 f64로 지정됩니다.

    let apple = 1.234;   // f64

만일, f32를 사용하기 위해 다음 코드와 같이 `:f32’로 명시해야 합니다.

    let apple:f32 = 1.234;   // f32

1.3 boolean#

Boolean type은 true 또는 false만 가질 수 있으며, 1 byte 크기입니다.
다음 코드와 같이 Boolean type 변수를 생성할 수 있습니다.

    let apple = true;
    let apple:bool = true;

1.4 char#

char는 문자 하나를 표현하는 Type 이며, 작은 따옴표('a')를 사용합니다.
※ 큰 따옴표("a")를 사용하면 문자열 입니다. char가 아닙니다.

Rust의 char는 유니코드 스칼라값으로 4-byte 크기이며 다국어 및 이모지 문자를 저장할 수 있습니다.
※ C/C++ 언어의 1-byte 크기인 char 와 혼돈하지 마세요.

다음과 같이 char type 변수를 생성할 수 있습니다.

    let banana = 'A';
    let banana:char = 'A';
    let banana = '김';
    let banana = '🐱';

 

2. Compound type#

Compound type(복합 타입)은 여러 Type의 값을 하나로 묶을 수 있습니다.
tuple 과 array 의 두 가지 type을 설명드리겠습니다.

2.1 tuple type#

다음 코드와 같이 괄호 ( )를 사용하여 여러 type의 값을 tuple로 묶을 수 있습니다.
tuple은 한번 선언되면 크기를 변경할 수 없습니다.

    let apple: (i32, f32, char) = (10, 1.23, 'A');
    let banana = (10, 1.23, 'A');

다음 코드의 let (a, b, c) = banana; 같이 tuple을 해체 할 수 있습니다.

    let banana = (10, 1.23, 'A');
    let (a, b, c) = banana;
    let sum = a + b;

    println!("a = {a}");
    println!("b = {b}");
    println!("c = {c}");
    println!("a + b = {sum}");

다음은 실행 결과 입니다.

a = 10
b = 1.23
c = A
a + b = 11.23

tuple은 다음 코드와 같이 .index를 사용하여 접근할 수 있습니다.
banana.010을 가리키고, banana.11.23을 가리킵니다.
첫번째 원소의 index는 0 입니다.

    let banana = (10, 1.23, 'A');

    println!("index 0 = {0}", banana.0);
    println!("index 1 = {0}", banana.1);
    println!("index 2 = {0}", banana.2);

다음은 실행 결과 입니다.

index 0 = 10
index 1 = 1.23
index 2 = A

만일, 다음 코드의 banana.99와 같이 tuple의 index 범위를 벗어나는 경우 Runtime이 아닌 Compile 과정에서 오류를 발생 시킵니다.
이것은 SW의 Runtime 안정성을 향상 시킬 수 있습니다.

    let banana = (10, 1.23, 'A');
    println!("index 2 = {0}", banana.99);

다음은 실행 결과 입니다.

error[E0609]: no field `99` on type `({integer}, {float}, char)`
 --> code1.rs:5:38
  |
5 |     println!("index 2 = {0}", banana.99);
  |                                      ^^ unknown field

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0609`.

2.2 array type#

Array는 같은 타입의 요소들로만 구성되며 고정된 길이를 갖습니다.
배열을 생성하는 몇 가지 방법을 알아 봅시다.
다음 코드는 int type의 1, 2, 3 세개의 원소를 가지는 Array을 만드는 예제 입니다.

    let arr = [1, 2, 3];

다음 코드와 같이 type과 size를 명시하여 Array를 생성할 수 있습니다.

    let arr:[i32; 3] = [1, 2, 3];

Array의 원소에 접근할 때는 다음 코드의 arr[0]과 같이 Index로 접근할 수 있습니다.

    let arr = [1, 2, 3];

    println!("{}", arr[0]);
    println!("{}", arr[1]);

만일 다음 코드의 arr[9]와 같이 Array 범위를 벗어나는 Index를 하드코딩 하는 경우 컴파일 과정에서 에러를 발생시킵니다.
이것은 런타임 오류를 사전에 방지하는데 도움을 줍니다.

    let mut arr = [1, 2, 3];

    arr[9] = 99;

다음은 실행 결과 입니다.

error: this operation will panic at runtime
  --> code1.rs:10:5
   |
10 |     arr[9] = 99;
   |     ^^^^^^ index out of bounds: the length is 3 but the index is 9
   |
   = note: `#[deny(unconditional_panic)]` on by default

error: aborting due to 1 previous error

하지만, 다음 코드와 같이 Index가 하드코딩 되지 않고 변수일 경우 컴파일 과정에서 오류가 발생하지 않습니다.
Runtime에서 Panic을 발생시킵니다.

    let mut arr = [1, 2, 3];

    for i in 10..20 { 
        arr[i] = 99;
    }

다음은 실행 결과 입니다.

thread 'main' panicked at code1.rs:7:9:
index out of bounds: the len is 3 but the index is 10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace