![Rust 걸음마 떼기 (3) - 일반 프로그래밍 개념을 rust에서는 어떻게 다루는가](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchsfI8%2FbtsAGXHmMo0%2FkshezYJtkPLESXev3waOjk%2Fimg.png)
2023.11.21 - [백엔드/Rust] - Rust 걸음마 떼기 (2) - 변수 선언, 입력, 비교
변수, 기본타입, 함수, 주석 그리고 흐름제어 등에 대해서 알아본다.
변수와 가변성
기본적으로 변수는 변경이 불가능하다. (immutable)
불변 변수를 선언하면 일단 변수값에 한번 값을 할당 한 이후에는 값을 변경할 수 없다.
fn main(){
let x = 5;
println!("x의값 : {}",x);
x = 6;
println!("x의값 : {}",x);
}
위의 코드를 실행해보면 오류가 발생한다.
![](https://blog.kakaocdn.net/dn/oD4QW/btsAJfU3NxS/oGKvPMkogmsgNKuWAhtpT0/img.png)
불변 변수를 두번 할당했기 때문에 오류가 발생했다.
개발자가 예측 못한(의도하지 않은) 지점에서의 버그실행을 줄여 줄 수 있기 때문에
이걸 컴파일 시점에서 잡아주는게 상당한 장점이라고 볼 수 있겠다.
즉, 코드를 읽는 사람 입장에서 코드를 쓴 사람의 개발 의도를 쉽게 파악 할 수 있다.
반대로 가변성이 필요하다면?
mut을 사용한다.
fn main(){
let mut x = 5;
println!("x의값 : {}",x);
x = 6;
println!("x의값 : {}",x);
}
![](https://blog.kakaocdn.net/dn/b3Fc0S/btsAFuTeEmu/s4LNDjzq9skaW8MzyRRE8k/img.png)
그럼 변수와 상수의 차이점은 뭔가?
- 상수에는 mut 키워드를 사용할 수 없다.
- 상수는 let 키워드 대신에 const 키워드로 선언하며, 할당할 값의 타입을 반드시 지정해야한다.
- 상수는 전역 범위를 비롯해서 어떤 범위에서도 선언가능하다.
- 상수는 반드시 상수 표현식을 통해서 할당해야하며, 함수 호출의 결과나 기타 런타임 연산으로 얻은 값을 사용할 수 없다.
다음 예제는 MAX_POINTS (러스트에서는 상수이름에 대문자만 사용하며, 단어사이에 밑줄을 추가하는 규칙을 가지고있다.
) 라는 상수에 100,000이라는 값을 할당한다.
const MAX_POINTS: u32 = 100_000;
또한, 밑줄은 숫자의 리터럴 가독성을 높이기 위해 자릿수 구분시에도 사용할 수 있다.
변수 가리기
이전에 선언한 변수는 새로 선언한 변수 때문에 가려진다.
(첫번째 변수가 두번째 변수에의해 가려졌다고 표현한다.)
fn main(){
let x = 5;
let x = x+1;
let x = x*2;
println!("x의값 : {} ",x);
}
변수가리기는 mut 키워드를 이용하는 방법과 다르다.
(첫 번째 let x에 mut에 붙이면 warning 발생한다.)
위는 let 키워드를 쓰지않고 값만 할당하면 컴파일 에러가 발생한다.
데이터 타입
러스트는 컴파일 시점에 모든 변수의 타입이 결정 되어야하는 정적 타입의 언어다.
여러타입을 사용할 수 있을때는 다음처럼 타입 어노테이션을 이용해서 명시해줘야한다.
let guess: u32 = "42".parse().expect("숫자가 아닙니다")
스칼라 타입
스칼라 타입은 하나의 값을 표현한다.
- 정수
- 부동 소수점 숫자
- 불리언
- 문자 등
네 종류의 스칼라 타입을 정의한다.
(1) 정수
크기
|
부호있음
|
부호없음
|
8bit
|
i8
|
u8
|
16bit
|
i16
|
u16
|
32bit
|
i32
|
u32
|
64
|
i64
|
u64
|
arch
|
isize
|
usize
|
(1-1) 정수 리터럴
바이트를 제외한 모든 숫자 리터럴에는 타입 접미사를 붙일 수 있으며,밑줄을 이용해 자리수를 표현할 수 있다.
숫자 리터럴
|
예시
|
Decimal
|
98_222
|
Hex
|
0xff
|
Octal
|
0o77
|
Binary
|
0b1111_0000
|
Byte (u8 전용)
|
b'A'
|
(2) 부동 소수점 타입
f32, f64가 있다.
fn main(){
let x = 2.0; //f64
let y: f32 = 3.0 //f32
}
(3) 사칙연산
fn main(){
//덧셈
let sum = 5 + 10;
//뺄셈
let difference = 95.5 -4.3;
//곱셈
let product = 4 * 30;
//나눗셈
let quotient = 56.8 /32.2
//나머지
let remainder = 43 % 5;
}
(4) 불리언 타입
fn main(){
let t = true;
let f : bool = false; //타입 애노테이션을 사용하는경우
}
(5) 문자 타입
char 타입
fn main(){
let c = 'z';
let z = 'z';
}
컴파운드 타입
하나의 타입으로 여러개의 값을 그룹화 한 타입이다.
튜플과 배열을 지원한다.
(1) 튜플 타입
fn main(){
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
(2) 배열 타입
튜플과 달리 배열은 모든요소가 같은 타입이여야한다.
fn main(){
let a = [1,2,3,4,5];
let b : [i32;5] = [1,2,3,4,5]; //배열에 i32 5개 존재한다
let c = [3;5]; // [3,3,3,3,3]과 동일
//접근은 다른 언어와 동일
let first = a[0];
let second = a[1];
//잘못된 인덱스에 접근하면 컴파일 에러는 안남, 런타임 에러가남
let index = 10;
let element = a[index];
}
함수
fn main(){
println!("hello");
another_function();
other_function(5,6);
}
fn another_function(){
println!("또 다른 함수");
}
//매개변수를 사용한 함수
fn other_function(x: i32, y:i32){
println!("x의 값 : {},x");
println!("y의 값 : {},y");
}
fn 으로 함수임을 알 수있음.
C처럼 함수를 먼저 선언하고 실행해야할 필요가 없음
실행하는곳보다 뒤에 선언되어도 상관 x
함수 본문의 구문과 표현식
- 함수 본문은 여러개의 구문으로 구성되며, 선택적으로 표현식으로 끝나기도한다.
다음은 하나의 구문으로 구성된 main 함수다.
fn main(){
let y = 6;
}
구문은 값을 리턴하지 않는다.
따라서, let 구문을 다른 변수에 대입 할 수 없다.
fn main(){
let x = (let y = 6); //불가능
}
let y = 6 구문은 값을 리턴하지 않으므로 x에 아무것도 대입되지 않는다.
표현식은 구문의 일부가 될 수있다.
let y = 6; 구문에서 6은 값6으로 평가되는 표현식이다.
함수의 호출 역시 표현식이다.
fn main(){
let x = 5;
let y = {
let x = 3;
x + 1 //여기는 세미콜론이 없다!!
}
println!("y의 값 {}",y);
}
표현식은 마지막에 세미콜론을 포함하지 않는다.
세미콜론이 마지막에 추가되면 표현식이 구문으로 바뀌어 값을 리턴하지 않는다.
값을 리턴하는 함수
함수는 자신을 호출하는 코드에 값을 지정할 수 있다.
리턴값에 이름을 부여하지는 않지만, 리턴할 값 의 타입은 화살표로 지정해야한다.
fn five() -> i32 {
5
}
fn main(){
let x = five();
println!("x의 값 {}",x);
}
또 다른 예시다.
fn plus_one(x: i32) -> i32 {
x + 1 //여기에 세미콜론을 붙이면 구문이 되고, 값이 아니라 빈 튜플인 ()를 리턴한다.
}
fn main(){
let x = five();
println!("x의 값 {}",x);
}
주석
// 이게 바로 주석이다
흐름 제어
if 표현식
fn main(){
let number = 3;
if number < 5 {
println!("조건이 일치합니다.");
} else {
println!("조건이 일치하지 않는다.");
}
}
if문의 조건은 반드시 불리언 타입을 리턴해야한다.
fn main(){
let number = 3;
if number {
println!("조건이 일치합니다.");
}
}
위는 에러를 발생시킨다.
![](https://blog.kakaocdn.net/dn/ZCBAw/btsAJhrN9jq/HKwQkG3vrGfTwnZOuUph3k/img.png)
사진 설명을 입력하세요.
(1) else if 를 이용하기
fn main(){
let number = 3;
if number % 4 ==0 {
println!("4로 나누어 떨어짐");
} else if number % 3 ==0 {
println!("3로 나누어 떨어짐");
} else if number % 2 ==0 {
println!("2로 나누어 떨어짐");
} else {
println!("4,3,2로 나누어 떨어지지않음.");
}
}
(2) let 구문에서 if 표현식 사용하기
fn main(){
let condition = true;
let number = if condition {
5
} else {
6
};
}
값은 5다.
다음은 에러를 발생시킨다.
fn main(){
let condition = true;
let number = if condition {
5
} else {
"six"
};
}
왜냐면 리턴하는 결과는 모두 같은 타입이어야 하기 때문.
루프를 이용한 반복
fn main(){
loop {
println!("무한루프다!");
}
}
(1) 루프에서 값 리턴하기
break 뒤에 리턴할 값을 추가하면된다.
fn main(){
let mut counter = 0;
let result = loop {
counter += 1;
if counter ==10 {
break counter * 2;
}
}
println!("the result is {}",result);
}
(2) while을 이용한 조건 루프
fn main(){
let mut number = 3;
while number != 0 {
println!("{}",number);
number = number -1;
}
println!("발사!");
}
(3) for을 이용한 각 요소 반복처리
fn main(){
let a = [1,2,3,4,5];
for element in a.iter() {
println!("요소의 값: {}", element);
}
}
fn main(){
//위의 while문과 동일하다.
for number in (1..4).rev() {
println!("{}", number);
}
println!("발사!");
}
rev()는 범위 뒤집기임.
'백엔드 > Rust' 카테고리의 다른 글
Rust with Flutter Tutorial (4) | 2023.11.21 |
---|---|
Rust 걸음마 떼기 (5) - Rust의 구조체 (2) | 2023.11.21 |
Rust 걸음마 떼기 (4) - 소유권 (러스트의 메모리 관리) (2) | 2023.11.21 |
Rust 걸음마 떼기 (2) - 변수 선언, 입력, 비교 (2) | 2023.11.21 |
Rust 걸음마 떼기 (1) - Rust 설치 및 실행 (0) | 2023.11.21 |
개발 및 IT 관련 포스팅을 작성 하는 블로그입니다.
IT 기술 및 개인 개발에 대한 내용을 작성하는 블로그입니다. 많은 분들과 소통하며 의견을 나누고 싶습니다.