데이터 타입(Data Type)

데이터 타입은 값이 가지는 특성이라고

할 수 있습니다. 정수냐 부동소수점 수

(실수를 컴퓨터로 표현한 것)냐의 다양한

형태에 따라 러스트 컴파일러가 값을

취급하는 방식이 달라지게 됩니다.

 

러스트는 컴파일 언어입니다.

정적 타입 언어(statically typed language) 라고 하는데

컴파일할 때 모든 변수들의 타입이 정해져야 합니다.

이는 프로그래머가 소스코드 작성시 타입이

정확하게 명시되야 한다는 뜻 입니다.

적어도 컴파일러가 추론(infer)이 가능해야 

컴파일이 될 겁니다. 정적 타입 언어의 반대는

동적 타입 언어(dynamically typed language)로

파이썬, 자바스크립트 같은 언어는

런타임에 데이터 타입이 확정됩니다.

 

러스트의 데이터 타입

러스트에는 스칼라 타입(scalar)와 복합 타입(compound)

두 종류의 데이터 타입이 있습니다.

어렵게 들리지만 스칼라는 단일 값(single value)을

표현하고 복합 타입은 튜플이나 배열 같이

다중 값(multiple values)을 저장하는 타입입니다.

 

내용을 들여다 보면 C나 다른 언어들과 비슷합니다.

 

정수형(Integer Types)

정수형은 가장 기본적인 데이터 타입입니다.

let 키워드를 사용해서 선언합니다.

 

let 변수이름: 타입 = 초기화값;

 

의 형식입니다. mut 키워드 없이는 값을

변경할 수 없으니 주의합니다.

 

fn main() {

    println!("\n[Rust Tutrorial 1 - Integer]");

    let my_favorite_int: i32 = 23;

    println!("- My Favorite Integer is {}", my_favorite_int);

    // you can't possibly assign a value to immutable variable
    // my_favorite_int = 40;
    
    let mut mutable_int: i64 = 156;
    println!("- mutable int : {}", mutable_int);

    // you can change the variable with mut keyword
    mutable_int = 256;

    println!("- mutable int : {}", mutable_int);
}

 

i32 는 타입을 표시한 것 입니다. 암호같지만

내용을 이해하면 의미가 명확합니다.

부호있는 정수로는 i8, i16, i32, i64, i128가 있는데

i는 인티저(integer - 정수)를 표시하고 뒤의 숫자는

비트를 의미합니다. 즉 i8은 부호있는 정수 8비트입니다.

 

부호가 없는 정수는 u로 표시합니다. u는 언사인드 인티저

(unsigned integer)를 의미하며 u8, u16, u32, u64, u128 입니다.

 

isize 와 usize는 실행하는 컴퓨터의 아키텍쳐를 따릅니다.

32비트냐 64비트냐에 따라 달라집니다.

 

다음 예제는 정수형 값의 범위를 출력합니다.

fn main() {
    println!("\n[Rust Tutrorial]");

    println!("--- Integer Types Signed ---\n");

    println!("  i8 type Max : {:>20}", i8::MAX);
    println!("  i8 type Min : {:>20}", i8::MIN);

    println!(" i16 type Max : {:>20}", i16::MAX);
    println!(" i16 type Min : {:>20}", i16::MIN);

    println!(" i32 type Max : {:>20}", i32::MAX);
    println!(" i32 type Min : {:>20}", i32::MIN);

    println!(" i64 type Max : {:>20}", i64::MAX);
    println!(" i64 type Min : {:>20}", i64::MIN);

    println!("i128 type Max : {:>45}", i128::MAX);
    println!("i128 type Min : {:>45}", i128::MIN);

    println!("isize type Max : {:>45}", isize::MAX);
    println!("isize type Min : {:>45}", isize::MIN);

    println!("\n--- Integer Types Unsigned ---\n");

    println!("  u8 type Max : {:>20}", u8::MAX);
    println!("  u8 type Min : {:>20}", u8::MIN);

    println!(" u16 type Max : {:>20}", u16::MAX);
    println!(" u16 type Min : {:>20}", u16::MIN);

    println!(" u32 type Max : {:>20}", u32::MAX);
    println!(" u32 type Min : {:>20}", u32::MIN);

    println!(" u64 type Max : {:>20}", u64::MAX);
    println!(" u64 type Min : {:>20}", u64::MIN);

    println!("u128 type Max : {:>45}", u128::MAX);
    println!("u128 type Min : {:>45}", u128::MIN);

    println!("usize type Max : {:>45}", usize::MAX);
    println!("usize type Min : {:>45}", usize::MIN);
}

 

결과는 다음과 같습니다.

러스트는 시스템 프로그래밍 언어기 때문에

이렇게 비트를 명시하는 타입이름은 기존 언어들에

비해 하드웨어적으로 명확하게 느껴집니다.

 

기존 언어들에 비해 다소 생소한 방식이지만

러스트는 미래에는 C언어를 대체할지도

모르기 때문에 익숙해질 필요가 있을것 같습니다.

 

[Rust Tutrorial]
--- Integer Types Signed ---

  i8 type Max :                  127
  i8 type Min :                 -128
 i16 type Max :                32767
 i16 type Min :               -32768
 i32 type Max :           2147483647
 i32 type Min :          -2147483648
 i64 type Max :  9223372036854775807
 i64 type Min : -9223372036854775808
i128 type Max :       170141183460469231731687303715884105727
i128 type Min :      -170141183460469231731687303715884105728
isize type Max :                           9223372036854775807
isize type Min :                          -9223372036854775808

--- Integer Types Unsigned ---

  u8 type Max :                  255
  u8 type Min :                    0
 u16 type Max :                65535
 u16 type Min :                    0
 u32 type Max :           4294967295
 u32 type Min :                    0
 u64 type Max : 18446744073709551615
 u64 type Min :                    0
u128 type Max :       340282366920938463463374607431768211455
u128 type Min :                                             0
usize type Max :                          18446744073709551615
usize type Min :                                             0

러스트의 기본 정수 타입은 i32 입니다. (32비트 정수)

 

정수형 오버플로우 문제

오버플로우는 타입의 한계를 벗어날 때 발생합니다.

예를 들어 u8 은 0~255까지인데 255에서1을 더하면

표현 범위를 벗어납니다. 디버그 모드의 런타임에서는

에러가 발생합니다. (panic) 오버플로우는 --release

모드에서는 에러를 발생시키지 않기 때문에 주의를 요합니다.

 

fn main() {

    println!("\n[Rust Tutrorial 1 - Integer]");
    println!("*Integer Overflow Problem");

    let mut overflow_u8: u8 = 255;

    println!("overflow_u8 : {}", overflow_u8);
    
    // runtime error will occur
    // use 'cargo run --release' to avoid program panic 
    overflow_u8 = overflow_u8 + 1;
    println!("overflow_u8 + 1 : {}", overflow_u8);

}
>> 디버그 모드


[Rust Tutrorial 1 - Integer]
*Integer Overflow Problem
overflow_u8 : 255
thread 'main' panicked at 'attempt to add with overflow', src\main.rs:10:19      
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

>> 릴리즈 모드

[Rust Tutrorial 1 - Integer]
*Integer Overflow Problem
overflow_u8 : 255
overflow_u8 + 1 : 0

 

let 키워드

러스트에서 let 키워드는 값을 변수에 할당합니다.

 

이것을 let statement 라고 합니다.

 

let은 현재의 범위(scope)에 변수를 생성합니다.

러스트는 정적 언어지만 데이터 타입을

추론(infer)할 수 있습니다. 가능하면 확실한

타입을 명시하는 것은 좋은 습관입니다.

 

데이터 타입을 명시하지 않으면 컴파일러는

추론해야 하고 대체로 단일값(single value)에

대해서는 정확합니다.

fn main() {

    println!("\n[Rust Tutrorial - let keyword]");

    let var1: i32 = 126;
    let var2 = var1 + 15000;

    let true_or_false = true;

    let my_array = [1,3,5];

    let my_tuple:(i8, i8) = (2, 4);

    println!("var1 : {}", var1);
    println!("var2 : {}", var2);
    println!("true or false : {}", true_or_false);

    println!("my array : [{}, {}, {}]", my_array[0], my_array[1], my_array[2]);

    println!("my tuple : ({}, {}) ", my_tuple.0, my_tuple.1)

}
[Rust Tutrorial - let keyword]
var1 : 126
var2 : 15126
true or false : true
my array : [1, 3, 5]
my tuple : (2, 4)

 

공유하기

facebook twitter kakaoTalk kakaostory naver band