Updated lifetimes.md

AinL authored
revision a5f4957c4c97b1d3a347f3c53295139586810bb4
lifetimes
# 5.9. 수명 (Lifetimes) - 90%

이 가이드는 러스트의 소유권 시스템을 설명하는 세 가이드 중 하나입니다. 이는 러스트의 가장 고유하면서 매력적인 동시에 러스트 개발자들이 반드시 친숙해져야 하는 특징입니다. 소유권을 통해 러스트는 스스로의 가장 거대한 목표인 메모리 안정성을 성취해냅니다. 관련된 몇가지 개념들이 있는데, 각각을 설명하는 장이 존재합니다. 다음과 같죠:

* 핵심 개념인 [소유권][ownership]
* [빌림][borrowing], 그리고 관련된 특징인 '참조'
* 여러분이 지금 읽고 계시는 수명

이 세 장들은 연관되어 있고, 순서대로 작성되어 있습니다. 소유권 시스템을 이해하기 위해선 세 장을 모두 필요로 할 것입니다.

[ownership]: ownership.html
[borrowing]: references-and-borrowing.html


## 개괄

세부사항을 살펴보기 전에, 소유권 시스템에 관한 두 가지 중요한 점을 짚고 넘어가겠습니다.

러스트는 안정성과 속도에 초점을 맞추고 있고, 이러한 목표들을 많은 '무비용 추상화 _zero-cost abstraction_'들을 통해 이루어냅니다. 다시 말해, 러스트에서 추상화는 그것이 작동하기 위해 필요한 최소한의 비용만을 필요로 합니다. 소유권 시스템은 무비용 추상화의 대표적인 예입니다. 이 가이드에서 이야기할 모든 분석들은 _컴파일 타임 내에 _이루어집니다. 이러한 기능들을 사용하기 위해 런타임에서 비용을 치를 필요는 없다는 이야기죠.

하지만, 이 시스템 역시 치뤄야할 비용은 있기 마련인데, 바로 학습 곡선입니다. 러스트를 처음 접하는 많은 사용자들은 작성자는 아무 문제가 없다고 생각하는 프로그램을 러스트 컴파일러가 컴파일하기 거부하는 현상에 맞닥뜨립니다. 우리가 '소유권 검사기와의 싸움'이라고 부르는 현상이죠. 이는 보통 소유권이 어떻게 동작해야 하는 지에 대한 프로그래머의 생각과 실제 러스트가 구현하는 규칙들이 다르기 때문에 발생합니다. 이 글을 읽고 있는 당신도 처음엔 비슷한 경험을 할지 모릅니다. 좋은 소식은, 이러한 소유권 시스템 규칙들과 함께 작업을 하면 할수록 소유권 검사기와 싸울 일은 점점 적어진다고 다수의 숙련된 러스트 개발자들이 말한다는 거죠.

그걸 명심하시고, 수명에 대해 배워봅시다.

# 수명

소유권자는 따로 있는 리소스에 대한 참조를 빌려주는 일은 꽤 복잡해질 수 있습니다. 예를 들어, 다음 일련의 명령을 생각해보세요.

- 제가 어떤 리소스에 대한 제어권을 얻습니다.
- 그리고 그 리소스에 대한 참조를 당신에게 빌려주는거죠.
- 당신이 그 참조를 아직 들고 있는 시점에서, 제가 그 리소스로 할 일을 마쳤다고 판단하고, 해당 리소스의 할당을 해제합니다.
- 그 후, 당신이 그 리소스를 사용하기로 마음먹습니다.

아이구 이런! 당신의 참조는 이제 유효하지 않은 리소스를 가리키고 있습니다. 그 리소스가 메모리인 경우에, 이러한 현상은 댕글링 포인터(dangling pointer) 혹은 '해제 이후의 사용(use after free)'라고 불립니다.

이걸 고치기 위해, 우리는 위의 예제에서 3번째 단계가 일어난 후에는 4번째 단계가 절대 일어나지 않을 것을 보장해 줄 필요가 있겠죠. Rust의 소유권 시스템은 수명(lifetime)이라는 개념을 통해 그 일을 해냅니다. 수명은 어떤 참조가 어떤 유효 범위(scope)안에서만 유효한지를 나타냅니다.

참조를 인자로 받는 함수가 있을 때, 그 참조의 수명을 명시적으로, 혹은 암묵적으로 나타낼 수 있습니다.

```rust
// implicit
fn foo(x: &i32) {
}

// explicit
fn bar<'a>(x: &'a i32) {
}
```

`'a`는 '수명 a'라고 읽습니다. 엄밀히 말하자면, 모든 참조는 자신과 관련된 수명을 가지고 있지만, 컴파일러가 있기 때문에 보통의 경우에는 당신이 그것을 굳이 언급하지 않아도 됩니다. 그 얘기를 좀 더 자세히 하기 전에, 일단 이 명시적 예제를 살펴보죠.

```rust,ignore
fn bar<'a>(...)
```

We previously talked a little about [function syntax][functions], but we didn’t
discuss the `<>`s after a function’s name. A function can have ‘generic
parameters’ between the `<>`s, of which lifetimes are one kind. We’ll discuss
other kinds of generics [later in the book][generics], but for now, let’s
just focus on the lifetimes aspect
이전에 간단히 [함수 문법][functions]에 대해 설명 했었는데, 하지만 함수이름 뒤의 `<>`에 대해서는 설명 하지 않았습니다. 함수의 '수명이 한 가지인 제널릭 인수'들을 `<>` 안에 선언 할 수 있습니다. 조금 뒤에서 다시 [여러가지 제널릭][generics]에 대해 설명하겠지만, 지금으로썬 그저 수명의 사용에 대해 집중 하도록 합시다.

[functions]: functions.html
[generics]: generics.html

수명을 선언하기 위해 `<>`를 이용합니다. `bar`라는 함수는 `'a`라고 불리는 하나의 수명을 가지고 있다고 말이죠. 만약 참조 매개변수가 두 개였다면, 아마 다음과 같았을 겁니다.

```rust,ignore
fn bar<'a, 'b>(...)
```

그 다음 우리의 매개변수 리스트에서, 우리가 명명한 수명들을 사용합니다.

```rust,ignore
...(x: &'a i32)
```

만약 `&mut` 참조를 원했다면, 다음과 같았겠죠.

```rust,ignore
...(x: &'a mut i32)
```

`&mut i32`와 `&'a mut i32`는 `&`와 `mut i32` 사이에 수명 `a`가 끼어들었다는 것을 제외하곤 동일합니다. 각각 `&mut i32`는 '`i32`로의 변경 가능한 참조', `&'a mut i32`는 '`'a'`의 수명을 갖는 `i32`로의 변경 가능한 참조' 라고 읽습니다.

# In `struct`s

[구조체][structs](`struct`)를 사용할 때에도 명시적 수명이 필요합니다.

```rust
struct Foo<'a> {
x: &'a i32,
}

fn main() {
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let f = Foo { x: y };

println!("{}", f.x);
}
```

[structs]: structs.html

위에서 볼 수 있듯, `struct` 역시 수명을 가질 수 있습니다. 함수와 비슷한 방식인데,

```rust
struct Foo<'a> {
# x: &'a i32,
# }
```

위와 같이 수명을 선언하고,

```rust
# struct Foo<'a> {
x: &'a i32,
# }
```

사용하는거죠. 여기서는 수명이 왜 필요한걸까요? `Foo`로의 참조가 그 안에 담겨있는 `i32`로의 참조보다 더 오래 살 수 없다는 것을 보장할 필요가 있기 때문입니다.

## `impl` blocks

Let’s implement a method on `Foo`:

```rust
struct Foo<'a> {
x: &'a i32,
}

impl<'a> Foo<'a> {
fn x(&self) -> &'a i32 { self.x }
}

fn main() {
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let f = Foo { x: y };

println!("x is: {}", f.x());
}
```

As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat
`'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>`
uses it.

## Multiple lifetimes

만약 참조가 여러개일때는, 다음과 같이 같은 수명을 주게 할 수 있습니다:

```rust
fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str {
# x
# }
```

이것은 `x`와 `y`가 같은 범위 안에 살아있고, 반환값 또한 같은 범위 안에 살아있다는 것을 나타냅니다. 만약 `x`와 `y`가 다른 수명을 가지게 하고 싶다면, 다음과 같이 쓰면 됩니다:

```rust
fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
# x
# }
```

이 예시에서, `x`와 `y`는 서로 다른 유효 범위를 지니지만, 반환 값은 `x`와 같은 수명을 가지고 있습니다.

## 유효 범위에 대해 생각하기

수명에 대해 좀 더 다뤄보기 위해 어떤 참조가 의미를 갖는(유효한) 유효 기간을 시각화해보죠. 다음과 같이요.

```rust
fn main() {
let y = &5; // -+ y goes into scope
// |
// stuff // |
// |
} // -+ y goes out of scope
```

앞서 언급한 `Foo`를 집어넣어 볼까요?

```rust
struct Foo<'a> {
x: &'a i32,
}

fn main() {
let y = &5; // -+ y goes into scope
let f = Foo { x: y }; // -+ f goes into scope
// stuff // |
// |
} // -+ f and y go out of scope
```

`f`는 `y`의 유효 기간 내에서만 살아있고, 따라서 아무런 문제가 없습니다. 하지만 만약 그렇지 않다면 어떨까요? 다음의 코드는 제대로 작동하지 않습니다.

```rust,ignore
struct Foo<'a> {
x: &'a i32,
}

fn main() {
let x; // -+ x goes into scope
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
// |
println!("{}", x); // |
} // -+ x goes out of scope
```

이쿠! 보시다시피, `f`와 `y`의 유효 범위는 `x`의 그것보다 짧습니다. 그럼에도 불구하고 `x = &f.x`를 통해 `x`를 이제 곧 유효 범위를 나가는 녀석을 가리키는 참조로 만들었죠.

명명된 수명(named lifetime)을 통해 유효 범위에게 이름을 줄 수 있습니다. 어떤 것에 대해 이야기하기 위해선 일단 이름부터 매겨야겠죠.

## 'static

'static'이라는 이름의 수명은 특별한 녀석입니다. 어떤 녀석이 전체 프로그램에 해당하는 수명을 갖고 있음을 나타내죠. 많은 Rust 프로그래머들은 문자열을 다루면서 `'static`을 처음 마주하게 됩니다.

```rust
let x: &'static str = "Hello, world.";
```

문자열 리터럴은 `&'static str` 타입을 갖고 있는데, 이는 참조가 항상 살아 있는 상태이기 때문입니다. 이 리터럴들은 최종 바이너리의 데이터 영역에 들어가죠. 또 다른 예제는 전역 함수입니다.

```rust
static FOO: i32 = 5;
let x: &'static i32 = &FOO;
```

위의 코드는 `i32`를 바이너리의 데이터 영역에 추가하고, `x`는 그에 대한 참조입니다.

## 수명의 생략(Lifetime Elision)

Rust는 함수 몸체에서는 강력한 로컬 타입 추론을 제공하지만, 아이템 시그니처들에 대해 그 자신에 기반해 그 타입을 추론해내는 것은 금지되어 있습니다. 하지만, 사용자의 편의를 위해 '수명의 생략'이라 불리는, 아주 제한적인 차선의 추론 알고리즘이 함수 시그니처에서의 타입 추론에 적용됩니다. 이 때, 이 추론은 세 개의 쉽게 외울 수 있고 명백한 규칙을 기반으로 *수명 인자들만을* 추론해내며, 함수 몸체와는 무관하게 이루어집니다. 수명의 생략을 통해, 그와 관련된 실제 타입들에 대한 정보를 가리지 않으면서도 아이템 시그니처를 보다 간략하게 작성할 수 있습니다. 마치 로컬 타입 추론처럼요.

수명의 생략에 대해 이야기 할 때, *입력 수명(input lifetime)*과 *출력 수명(output lifetime)*이라는 용어들이 사용됩니다. *입력 수명*이란 함수의 인자와 연관된 수명, *출력 수명*은 함수의 리턴 값과 연관된 수명을 의미합니다. 예를 들어, 다음 함수는 입력 수명을 가지고 있습니다.

```rust,ignore
fn foo<'a>(bar: &'a str)
```

이 녀석은 출력 수명을 가지고 있구요.

```rust,ignore
fn foo<'a>() -> &'a str
```

다음에 나올 함수는 두 수명을 모두 갖고 있네요.

```rust,ignore
fn foo<'a>(bar: &'a str) -> &'a str
```

앞서 언급한 세 가지 규칙은 다음과 같습니다.

* 함수의 매개변수에서 생략된 수명들은 각각 별개의 수명 인자가 됩니다.

* (생략되었건 아니건) 만약 정확히 한 개의 입력 수명만이 존재한다면, 그 수명이 해당 함수의 리턴 값들의 모든 생략된 수명에 할당됩니다.

* 만약 다수의 입력 수명이 있지만 그 중 하나가 `&self`나 `&mut self`라면, `self`의 수명이 모든 생략된 출력 수명에 할당됩니다.

위의 규칙들로 추론해 낼 수 없는 경우, 출력 수명의 생략은 에러를 발생시킵니다.

### 예제

다음은 생략된 수명을 갖는 함수들의 예제들입니다. 각각의 수명이 생략된 형태의 함수들을 각각 수명이 생략되지 않고 확장된(expanded) 형태와 짝지어 놓았으니, 참고하세요.

```rust,ignore
fn print(s: &str); // elided
fn print<'a>(s: &'a str); // expanded

fn debug(lvl: u32, s: &str); // elided
fn debug<'a>(lvl: u32, s: &'a str); // expanded

// In the preceding example, `lvl` doesn’t need a lifetime because it’s not a
// reference (`&`). Only things relating to references (such as a `struct`
// which contains a reference) need lifetimes.

fn substr(s: &str, until: u32) -> &str; // elided
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded

fn get_str() -> &str; // ILLEGAL, no inputs

fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous

fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded

fn args(&mut self, args: &[T]) -> &mut Command // elided
fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded

fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded