[Rust] 프로그래밍 컨셉

변수, 타입, 함수 등…

Kwoncheol Shin
7 min readMar 14, 2019
Photo by Brian Miller on Flickr

Rust는 프로그래밍 언어다. 다른 많은 언어들과 마찬가지로 함수와 변수의 조각들을 이용해 프로그램을 만들며 타입을 비롯한 여러가지 문법들이 존재한다.

이번 글에서는 이러한 Rust의 프로그래밍 컨셉들에 대해 이야기하려고 한다.

Identifier

Rust에서 변수나 함수의 이름은 ‘identifier’라고 불린다. 변수명은 아스키 문자열들로 이루어질 수 있으며 몇가지 규칙을 따라야 한다.

  1. 첫 번째 글자가 숫자나 기호가 아닌 알파벳인 경우
  • 나머지 글자로 알파벳, 숫자, _ 모두 사용 가능하다.
  • 한 글자만 사용해도 된다.

2. 첫 번째 글자가 _인 경우

  • 나머지 글자로 알파벳, 숫자, _ 모두 사용 가능하다.
  • 한 글자만 사용할 수 없다. _ 뒤에 알파벳이나 숫자를 사용해야 한다.

Rust가 미리 선점한 몇 가지 키워드는 identifier로 사용할 수 없다. 아래 페이지 참조

https://doc.rust-lang.org/book/appendix-01-keywords.html

Raw Identifier

Rust가 선점한 키워드들을 identifier로 사용하고 싶다면 Raw identifier로 선언하는 방법이 있다.

fn 은 Rust에서 함수를 선언하는 키워드이다. 이 이름을 Raw identifier로 선언하고 싶다면

let r#fn = "raw identifier for 'fn'!";fn r#match() { 
-- 중략 --
}

위와 같은 식으로 이름 앞에 r# 를 붙여서 사용할 수 있다.

변수 (variable)

이미 Rust를 경험해봤거나 이전에 내가 쓴 Rust로 게싱게임 만들기 를 읽었던 사람이라면 Rust의 변수는 기본적으로 immutable 하다는 것을 알고 있을 것이다. immutable 변수에는 값을 단 한 번만 할당할 수 있다. 선언시 값을 할당하지 않았다면 나중에 이를 할당하는 것은 가능하다. 다음 코드는 에러를 발생시킨다.

let var = 4;
var = 2;
>> error: cannot assign twice to immutable variable

만약 나중에 값을 재할당할 필요가 있다면 mut 이라는 키워드를 붙여줘야 한다.

let mut var = 4;
var = 2;
>> compiled!

변수(variable)와 상수(const)의 차이

그렇다면 immutable 변수와 const 키워드를 이용해 선언할 수 있는 상수와는 어떤 차이가 있는걸까?

첫 번째, const 에는 mut 키워드를 붙일 수 없다.

두 번째, const 는 선언시 무조건 값을 할당해야 하지만 변수는 그렇지 않다.

세 번째, const 는 타입을 꼭 명시해야 한다.

네 번째, const 는 런타임에 계산될 값을 할당할 수 없다. 작성자가 직접 값을 적어줘야한다. 함수의 반환값이나 다른 변수와의 계산결과를 값으로 할당할 수 없다.

쉐도잉 (Shadowing)

변수가 기본적으로 immutable 이라고 했지만 쉐도잉이라는 기능으로 같은 이름의 변수를 새로운 값으로 사용할 수 있다. 다음 코드를 보면 mut 키워드를 붙이지 않았지만 값을 새롭게 할당할 때 let 키워드를 다시 붙여 줌으로 새로운 값의 변수를 선언하고 있다.

let age = 43;
let age = "twenty two";

위와 같이 같은 이름의 변수를 다시 선언하는 것을 쉐도잉이라고 한다. 쉐도잉의 장점은 값의 의미는 같지만 타입이 다른 경우에도 여러 개의 변수를 선언하지 않아도 되게 해줬다는 것이다.

예를 들어, 위 예제의 경우 age_int , age_str 이런 식으로 선언했어야 하지만 쉐도잉을 통해 동일한 변수명을 사용하고 있다.

타입 (Type)

모든 변수는 타입을 가지고 있다. 상수의 경우 선언시 타입을 명시해줘야 하며 변수의 경우는 optional하다.

타입이 i32 인 경우 다음과 같이 선언할 수 있다.

const MAX_VAL: i32 = 100;
let age: i32 = 150;

이제 Rust타입은 크게 스칼라타입과 복합타입으로 나뉜다.

스칼라타입

  1. 숫자타입
  • i8 , i16 , i32 , i64 , i128

정수를 표현할 수 있는 integer 타입이다. 접두어로 i 대신 u 를 붙인다면 unsigned 변수를 선언할 수 있다. 접두어 뒤 숫자는 수의 표현범위를 뜻한다. 단위는 비트(bit)이다.

  • f32 , f64

실수를 표현할 수 있는 floating 타입이다. 요즘 컴퓨터에서는 f32f64 나 성능면에서 의미있는 차이를 만들어내지 않기 때문에 정확도가 더 높은 f64 를 사용하는 것을 추천한다.

2. 불리언타입 (Boolean)

  • bool

true 혹은 false 를 값으로 가질 수 있는 타입이다.

let isHuman: boolean = true;

3. 문자타입 (character)

  • char

Rust의 문자는 아스키문자뿐만 아니라 유니코드 스칼라 값까지 표현할 수 있다. 유니코드의 16⁴ 개의 문자를 표현할 수 있다! char 타입은 따옴표를 하나 붙여서 표현한다. (쌍따옴표는 문자열에서 쓰인다)

let alphabet_leader: char = 'a';

복합타입 (Compound)

  1. 튜플

튜플은 여러 개, 여러 타입의 변수를 하나로 묶어주는 역할을 한다. 다음과 같이 사용 가능하다.

let tup: (i32, f64, u8) = (500, 5.4, 1);

tup 변수를 다음과 같이 해체하는 것도 가능하다.

let (x, y, z) = tup;>> x, y, z에는 각각 500, 5.4, 1 값이 할당

또한 인덱스를 이용해 값에 접근할 수 있다. 인덱스를 쓰기 위해서는 튜플명 뒤에 .을 붙이고 인덱스번호를 넣으면 된다.

println!("Value x is {}", tup.0);>> "Value x is 500" 출력

2. 배열

Rust의 배열은 길이가 고정돼있다. 즉 처음 선언시 정해진 길이를 바꿀 수 없다는 것이다. 만약 그러한 기능이 필요하다면 Vector를 사용해야 한다. 배열 선언은 타입으로 [type; length] 와 같은 포맷을 사용해야 한다.

배열 요소들의 타입이 char , 길이가 5인 경우 다음과 같이 선언할 수 있다.

let arr: [char; 5] = [1,2,3,4,5];

배열 또한 인덱스로 접근할 수 있다. arr[0] 와 같은 형식으로.

만약 배열의 길이를 초과하는 인덱스로 접근한다면 Rust는 에러를 뱉는다. 여기서 배열이 길이를 처음 그대로 고정시키는 것의 장점이 나온다.

사용자가 직접 인덱스를 주어 접근할 경우 Rust는 우선 그 인덱스와 해당 배열의 길이를 비교한다. 그리고 인덱스가 배열 길이보다 크다면 에러를 반환하는 것이다.

함수 (Function)

Rust의 함수에서 가장 중요한 포인트는 statements, expressions 이다.

함수는 파라미터를 받을 수 있고 값을 반환할 수 있다. 이 때 받을 파라미터와 반환할 값이 있다면 함수 선언시 이를 모두 명시해줘야한다.

두 개의 정수를 전달받아 둘을 더한 결과를 실수로 반환하는 함수는 다음과 같이 선언할 수 있다.

let getIntsAndReturnFloat(x: i32, y: i32) -> f64 { }

중괄호 안에는 함수의 내용을 입력한다.

함수 내에서 값을 반환하기 위해서는 return 키워드를 사용해야 하는데 만약 반환타입이 있는 함수에서 값을 반환하지 않는다면 에러가 발생된다.

그런데 반환은 무조건 return 키워드만이 할 수 있는 일은 아니다.

return 키워드가 없다면 함수 내에서 마지막 expression의 값이 반환된다. expression이 무엇이냐면 x + 3 혹은 그냥 'c' 처럼 어떤 동작을 하는 것이 아닌 값을 표현하는 표현식이다.

expression의 뒤에는 세미콜론 ;을 붙이지 않는다.

다음 함수는 10을 반환한다.

fn tempFunc() -> i32 {
let value = 5;
value + 5
}

마지막 문장에서 마지막에 ; 를 붙이지 않았다. 이는 이 함수의 마지막 표현식이고 return 키워드를 사용한 곳이 없기 때문에 이 값이 함수의 결과로 반환된다.

expression은 함수를 선언할 때가 아닌 변수를 선언할 때도 사용할 수 있다. 변수선언시 아래와 같이 중괄호를 열면 런타임에 값을 계산해 expression을 통해 값을 할당할 수 있다.(return 키워드는 못쓴다)

let var = {
let first_value = 5;
first_value + 2
}

오늘 살펴본 것들은 사소하지만 Rust를 100% 활용하기 위해서 꼭 필요한 개념들이니 다시한번 훑어보며 개념을 익히길 바란다!

To be continued…💻

--

--