| 1 | 1 | [[분류:방법]] |
|---|
| 2 | | 러스트를 처음 써보는 사람을 위해 러스트북을 요약해보았다. |
|---|
| 3 | | == 소유권 == |
|---|
| 4 | | 러스트를 배울 때 나오면 가장 때려치고 싶게 만드는 원흉. 메모리를 바로바로 해지하는 언어 특성상 소유권은 메우 중요한 계념이다. |
|---|
| 5 | | === 함수에 넘기기 === |
|---|
| 6 | | 또한 어떤 함수에 인자로 값을 넘기면 그 값의 소유권은 만료된다.{{{#!syntax rust |
|---|
| 7 | | fn main () { |
|---|
| 8 | | let a:u8 = 0; |
|---|
| 9 | | take_ownership(a); |
|---|
| 10 | | println("{a}"); |
|---|
| 11 | | } |
|---|
| 12 | | fn take_ownership (a:u8) { |
|---|
| 13 | | } }}}이를 실행해도 컴파일 에러가 나는데 a를 함수에 넘긴 다음에 사용하려 하였기 때문이다. 이럴 때는 to_owned(), clone()등을 써서 값을 복사함으로서 해결할 수 있지만[* clone은 벡터, String등 실제 값을 가리키는 포인터를 복사하는 반면(shallow copy), toowned는 그 메모리 내용까지 복사한다.(deep copy)] 더 좋은 방법이 있다. |
|---|
| 14 | | |
|---|
| 15 | | 또한 Copy trait이 구현되어있다면, 함수에 넣을 시에 자동으로 값이 복사되어서 딱히 값을 복사하거나 할 필요가 없다.[* 그래서 사실 위의 예제를 실행해도 에러는 안난다. u8 type이 Copy trait을 구현하였기 때문] |
|---|
| 16 | | |
|---|
| 17 | | === 참조자 === |
|---|
| 18 | | 어떤 함수의 값을 넘길 때 |
|---|
| 19 | | {{{#!syntax rust |
|---|
| 20 | | fn main() { |
|---|
| 21 | | let a:u8 = 0 |
|---|
| 22 | | borrow_me(&a); |
|---|
| 23 | | println("{a}") |
|---|
| 24 | | } |
|---|
| 25 | | fn borrow_me (a:&u8) { |
|---|
| 26 | | } |
|---|
| 27 | | }}}이렇게 함수에 넘길 때 참조자(&)를 사용하면 소유권을 유지할 수 있다. |
|---|
| 28 | | == lifetime == |
|---|
| 29 | | '''러스트의 난이도를 높히는 주범''' 포인터가 혜지된 메모리를 가리키는 것을 방지하려 만들었다. 러스트라는 언어 자체가 null pointer exception[* dangling pointer라고 많이 불리는듯]을 피하려고 설계되었기 때문이다. |
|---|
| 30 | | === 스코프 === |
|---|
| 31 | | 가장 중요한 계념 중 하나는 스코프[* {랑 }사이] 밖을 벗어나면 스코프 안에서 정의된 변수는 사용할 수 없다인데 예를들어{{{#!syntax rust |
|---|
| 32 | | fn main () { |
|---|
| 33 | | { |
|---|
| 34 | | let a:u8 = 0; |
|---|
| 35 | | } |
|---|
| 36 | | println!("{a}"); |
|---|
| 37 | | } }}}를 실행하면 컴파일 에러가 난다.[* 런타임 에러가 아니다!] 왜냐하면 스코프 안에서 선언 된 a를 수명이 끝난 스코프 밖에서 값을 조회하였기 때문이다. |
|---|
| 38 | | === 제내릭 라이프타임 === |
|---|
| 39 | | ==== 참조 둘 중 하나를 반환하는 함수 ==== |
|---|
| 40 | | '''지옥의 시작''' |
|---|
| 41 | | {{{#!syntax rust |
|---|
| 42 | | fn longest<'a> (s1:&`a str,s2:&`a str) -> &`a str { |
|---|
| 43 | | if s1.len() > s2.len() { |
|---|
| 44 | | s1 |
|---|
| 45 | | } else { |
|---|
| 46 | | s2 |
|---|
| 47 | | } |
|---|
| 48 | | } }}} |
|---|
| 49 | | 함수 뒤에 꺽쇠 괄호가 있는 것을 볼 수 있는데 이렇게 생각하면 된다. |
|---|
| 50 | | {{{#!syntax rust |
|---|
| 51 | | fn any<T> (input:T) { |
|---|
| 52 | | //input은 어떤 타입이든 될 수 있음 |
|---|
| 53 | | } }}} |
|---|
| 54 | | 위의 예시처럼 `a는 어느 라이프타임이든 될 수 있다는 것이다. |
|---|
| 55 | | |
|---|
| 56 | | 다시 longest로 돌아가보자. 아하 longest 함수의 s1과 s2는 공통된 생명 주기를 가져야하고 리턴값의 생명주기도 같아야하구나.라는 사실을 알수 있다. 왜냐? |
|---|
| 2 | == 변수 == |
|---|
| 3 | 변수는 기본적으로 불변이다. 예를들어 |
|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 | 4 | {{{#!syntax rust |
|---|
| 58 | 5 | fn main () { |
|---|
| 59 | | let s1 = String::new(); |
|---|
| 60 | | let result; |
|---|
| 61 | | { |
|---|
| 62 | | let s2 = String::new(); |
|---|
| 63 | | result = longest(&s1, &s2); |
|---|
| 64 | | } |
|---|
| 65 | | println!("{result}"); |
|---|
| 6 | let a = "hello, "; |
|---|
| 7 | println!("{}", a); |
|---|
| 8 | a = "world!"; |
|---|
| 9 | println!("{}"); |
|---|
|
|
|
| 66 | 10 | } }}} |
|---|
| 67 | | 만약 위 코드에서 함수가 s2를 리턴한다면 어떤일이 벌어질지 생각해보자. |
|---|
| 11 | 이러한 코드가 있으면 컴파일 에러가 나는데 이유는 a가 불변인 변수이기 때문이다. |
|---|
| 68 | 12 | |
|---|
| 69 | | result를 조회 할 때 s2의 원본을 조회해야하는데 그게 스코프를 나가버려서 사라져버렸다. 따라서 null pointer가 된다. |
|---|
| 13 | 러스트가 기본적으로 불변 변수 형태를 채택하는 이유는 만약 변수가 불변인 것을 가정하고 프로그램을 만들었는데, 가변이라면 문제가 생길 수 있기 때문이다. ~~아니 그러면 변수가 아니지 않나~~ |
|---|
| 70 | 14 | |
|---|
| 71 | | 그러면 의문이 들 것이다. "아니 그러면 런타임 에러를 발생시키면 되잖아." 그런데 러스트는 그걸 하지 말라 만든 언어다. 언어 설계에 모순이 생긴다. |
|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 | 러스트에서 변수를 가변으로 만들려면 let 키워드 뒤에 mut을 붙히면 된다. |
|---|
| 16 | {{{#!syntax rust |
|---|
| 17 | fn main () { |
|---|
| 18 | let mut a = "hello, "; |
|---|
| 19 | println!("{}", a); |
|---|
| 20 | a = "world!"; |
|---|
| 21 | println!("{}"); |
|---|
| 22 | } }}} |
|---|
| 23 | == 함수 선언 == |
|---|
| 24 | 함수는 fn키워드로 선언할 수 있다. |
|---|
| 25 | {{{#!syntax rust |
|---|
| 26 | //함수는 기본적으로 snake_case로 작명하여야 한다. |
|---|
| 27 | fn a_function { |
|---|
| 28 | println!("in function!"); |
|---|
| 29 | } }}} |
|---|
| 72 | 30 | |
|---|
| 73 | | "아니 그러면 애초부터 result를 longest의 리턴으로 못넣게 하면 되잖아." 그게 수명주기 명시다. 지금 longest의 리턴값은 s2의 수명주기와 같다.[* `a로 수명주기를 명시한것 중이서 s2가 수명이 가장 짧기 때문] |
|---|
| 74 | | |
|---|
| 75 | | "그럼 인풋중 수명이 더 짧은 것을 리턴의 수명으로 정하면 되잖아?" [[https://github.com/dtolnay/rust-faq#why-arent-function-signatures-inferred|할 수 있는데 안한다]](...) ~~아니 왜요?~~ |
|---|
| 76 | | [각주] |
|---|
| 77 | | ---- |
|---|
| 78 | | [include(틀:문서 가져옴,문서=Rust,버전=26)] |
|---|