티스토리 뷰
다음의 C 코드를 Rust로 바꾸어 보겠습니다. 배열과 for 루프, 그리고 함수에 배열을 넘기는 것이 포함됩니다.
void analyze_slice(int arr[], int len)
{
printf("arr[0] = %d, 길이: %d\n", arr[0], len);
}
void main()
{
int xs[] = {1, 2, 3, 4, 5};
int ys[500] = {0};
printf("xs 배열의 크기: {}", sizeof(xs)/sizeof(int));
// 배열을 대여 - 함수 호출
analyze_slice(xs, 5);
for (int x=0; x < 500; x++) {
ys[x] = x;
}
// 배열의 슬라이스를 대여
analyze_slice(&ys[5], 3);
}
배열을 2개 선언하고 선언 초기화와 for 루프를 이용한 초기화 예를 보여줍니다. 그리고 analyze_slice라는 함수에서는 주소를 포인터로 받아 첫 번째 칸의 값을 출력합니다. 여기서 두 번째 함수 호출에서는 &ys[5]을 보냈는데, 이것은 함수이 여섯 번째 칸의 주소를 나타냅니다. 그럼 받는 쪽에서는 그 위치부터의 배열을 arr로 받게 됩니다. 또한 C 언어에서는 배열을 포인터로 넘기므로 크기를 별도의 매개변수로 보내야 합니다.
그럼 먼저 배열의 선언부와 초기화 부분을 살펴보도록 하겠습니다.
// 고정크기 배열 (let xs:[i32; 5]의 생략)
let xs = [1, 2, 3, 4, 5];
// 모든 값을 0으로 초기화
let mut ys: [i32; 500] = [0; 500];
첫 줄은 고정크기 배열의 선언을 보여줍니다. C와 마찬가지로 배열의 초기값을 나열하면 크기가 자동으로 설정됩니다. 그리고 숫자의 경우 디폴트로 i32 타입으로 설정됩니다.
두 번째 선언은 배열을 500칸 선언하며 모두 0으로 초기화하는 것을 보여줍니다. 이것은 C 코드에서의 int ys[500]={0};에 대응합니다. 또한 ys는 값을 나중에 바꿀 수 있어야 하므로 앞에 mut라고 써주었습니다.
fn analyze_slice(slice: &[i32]) {
println!("[0] = {}, 길이: {}", slice[0], slice.len());
}
...
analyze_slice(&xs);
다음은 함수에 배열을 매개변수로 보내는 방법입니다. 배열을 참조로 보내서 해당 주소의 값을 읽게 하기 위해 &[i32]를 썼습니다. 이것은 C 언어에서 (int slice[])과 같은 의미가 됩니다. 단, 러스트에서는 배열의 크기를 배열 자체가 알고 있으므로 C 처럼 별도로 길이를 매개변수로 보낼 필요가 없습니다. 러스트 함수에서는 slice 참조를 대여해서 받았다가 함수가 끝나면 돌려주게 됩니다.
다음으로 ys 배열의 초기값을 설정하는 for 루프를 살펴보겠습니다.
for x in 0..500 {
ys[x] = i32::try_from(x).unwrap();
}
/* for (int x=0; x < 500; x++) {
ys[x] = x;
}
*/
여기서 C와는 상당히 다른 구문이 등장합니다. for x in 0..500은 파이썬에서 보았던 구문입니다. x 변수가 0부터 499까지의 값을 차례로 반복하게 됩니다. 다음 줄에서는 C처럼 간단히 ys[x] = x; 라고 쓸 수가 없습니다. 러스트의 복잡한 타입의 관계를 알아야 되는데, 여기서 for 루프 인덱스는 usize라는 타입을 가지게 되고 ys[x]는 i32 타입입니다. 이 둘간에 자동 변환은 물론이고 그냥 i32.from(x)라고 써서 변환하는 것도 안 됩니다. 왜냐하면 overflow가 생길 여지가 있기 때문입니다. 그래서 try_from과 unwrap을 써서 형변환을 해주고 있습니다. 게다가 use로 try_from을 임포트해 주어야 합니다.
그럼 마지막으로 ys 배열의 5번째부터를 배열로 넘기는 것을 살펴보겠습니다. 이것은 C 언어에서는 스트링의 일부분이나 배열의 일부를 나타내기 위해 많이 사용합니다. 러스트에서도 이것을 슬라이스라는 개념으로 중요하게 업그레이드했습니다. 배열의 일부를 자유롭게 표현할 수있게 됩니다.
analyze_slice(&ys[5 .. 8]);
그리고 그 슬라이스를 대여해서 배열에게 전달합니다. 슬라이스는 다음과 같은 그림으로 표현될 수 있습니다.
이 그림은 문자열에 대한 슬라이스를 보여주지만 개념은 같습니다. 배열 s에 대해 중간부터 길이 5의 슬라이스를 나타내는 world라는 변수가 생긴 것이지요. 이 때 world는 참조를 대여한 것이라고 볼 수 있습니다.
위의 ys 배열 슬라이스 참조도 마찬가지입니다. 5..8로 두번째 칸부터 세 개를 슬라이스로 함수에 참조를 대여합니다. 그럼 함수 안에서는 그것이 배열로 온 것과 같습니다. 길이는 3으로 설정되어 있겠지요.
이제 전체를 하나의 코드로 모아서 살펴보면 다음과 같습니다. 이 코드를 rust playground에서 실행해 보세요.
use std::convert::TryFrom;
// 배열을 가져와서 첫 원소와 길이를 출력
fn analyze_slice(slice: &[i32]) {
println!("[0] = {}, 길이: {}", slice[0], slice.len());
}
fn main() {
// 고정크기 배열 (let xs:[i32; 5]의 생략)
let xs = [1, 2, 3, 4, 5];
// 모든 값을 0으로 초기화
let mut ys: [i32; 500] = [0; 500];
// 배열의 크기 출력
println!("배열의 크기: {}", xs.len());
// 배열을 대여 - 함수 호출
analyze_slice(&xs);
for x in 0..500 {
ys[x] = i32::try_from(x).unwrap();
}
// 배열의 슬라이스를 대여
analyze_slice(&ys[5 .. 8]);
}
'Rust 프로그래밍' 카테고리의 다른 글
간단한 C 코드를 Rust 프로그램으로 바꾸기 (1) (0) | 2020.07.15 |
---|---|
Rust - 참조 변수와 대여 (0) | 2020.07.06 |
Rust - 메모리를 자동으로 제때 해지한다? (0) | 2020.07.05 |
Rust는 변수가 왜 불변이라는 걸까? (0) | 2020.07.03 |
- Total
- Today
- Yesterday
- 이터레이터
- 스트링
- 스트링 +
- Camel Style
- C++ 클래스
- contentEquals
- 동적바인딩
- follow
- python example
- 이터러블
- typedef
- sort key
- ToString
- 패턴
- indexof
- rust
- CompareTo
- format
- 콜렉션
- contains
- Lazy evaluation
- 지연계산
- python exercise
- zip
- comparable
- 자바regex
- TypeError
- Iterator
- APPEND
- max
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |