[Rust] 1.65.0 업데이트 발표 (번역)

https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html

우리 러스트 팀은 새 버전 [1.65.0]을 발표하게 돼서 정말 기쁩니다!
러스트는 누구든 믿음직하고 효과적인 소프트웨어를 만들 수 있게 도와주는 끝내주는 언어입니다.

ㅡㅡㅡㅡㅡㅡㅡ
새로운 Rust 릴리스에 대해 자세히 알아보기 전에, Mahsa Amini의 비극적인 죽음과 이란의 종교경찰에 의한 많은 사람들의 죽음과 폭력에 주목하고 싶습니다. 자세한 내용은 https://en.wikipedia.org/wiki/Mahsa_Amini_protests를 참조하세요. 우리는 인권을 위해 투쟁하는 이란 국민들과 연대합니다.
ㅡㅡㅡㅡㅡㅡㅡ

만약 rustup을 통해서 Rust의 이전버전을 설치해놓은 상대라면, 업데이트는 아주 쉽습니다. 그냥 이렇게 치면 돼요.
rustup update stable

rustup을 설치한 적이 없다면, 우리 웹사이트의 설치 페이지에서 받을 수 있습니다. 그리고 깃허브에서 이번 버전에 대한 릴리즈 노트를 참조해보세요.

미래의 릴리즈를 테스트해서 러스트 팀을 돕고 싶다면, 로컬에서 베타 채널(rustup default beta) 또는 nightly 채널(rustup default nightly)로 업데이트하는 것을 고려할 수 있습니다.

버그를 발견했다면 리포트해주세요!




1.65.0 stable에는 무엇이 있나요?


Generic associated types (GATs)

라이프타임, 타입, const generic은 관련된(associated) 타입에서 정의될 수 있습니다.
이런 식이죠.

**trait Foo { **
** type Bar<'x>; **
**} **

이게 얼마나 유용할 수 있는지는 말로만 표현하기 어렵습니다.
예시를 한번 보죠. 트레잇 정의입니다.

/// Self에서 빌려올 수 있는 Iterator****
**trait LendingIterator { **
** type Item<'a> where Self: 'a; **


** fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; **
**} **


/// 포인터 타입에 대해 제너릭이 될 수 있게 하려면
/// RcArc와 같은 스마트 포인터를 통해 구현할 수 있습니다.****
**trait PointerFamily { **
** type Pointer: Deref<Target = T>; **


** fn new(value: T) -> Self::Pointer; **
**} **


/// items의 배열을 빌릴 수 있습니다. **
/// 데이터를 연속적으로 저장할 필요가 없는 'NdArray'-like 타입에 유용합니다.
**
**trait BorrowArray { **
** type Array<'x, const N: usize> where Self: 'x; **


** fn borrow_array<'a, const N: usize>(&'a self) -> Self::Array<'a, N>; **
**} **

보다시피, GAT는 매우 다재다능하며 현재 작성할 수 없는 많은 패턴을 가능하게 합니다.

자세한 내용은 작년에 게시된 안정화 push를 알리는 게시물 또는 지난주에 게시된 안정화 발표 게시물을 확인하세요.
전자는 위의 몇 가지 예를 자세히 설명하는 반면 후자는 해당 안정화의 알려진 제한 사항에 대해 설명합니다.

더 자세한 내용은 nightly 레퍼런스원본 RFC(6.5년 전)의 associated type 섹션에서 찾을 수 있습니다.




let-else 구문

반박 가능한(refutable) 패턴과 해당 패턴이 일치하지 않을 때 실행되는 분기형 else 블록이 있는 새로운 형태의 let 문을 도입했습니다.

**let PATTERN: TYPE = EXPRESSION else { **
** DIVERGING_CODE; **
**}; **

일반적인 let 문은 항상 정적으로 일치한다고 알려진, 반박할 수 없는(irrefutable) 패턴만 사용할 수 있습니다.
이 패턴은 단일 변수 바인딩에되 쓰이지만 구조체, 튜플 및 배열과 같은 복합 타입의 압축을 풀 때 사용하기도 합니다.
하지만 이건 enum의 변형을 꺼내는 것과 같은 조건부 일치에는 사용할 수 없었죠.

let-else를 사용하면 반박 가능한(refutable) 패턴은 일반 let처럼 주변 범위의 변수를 일치시키고 바인딩할 수 있으며 패턴이 일치하지 않을 때 분기(예: break, return, paric!)할 수 있습니다.

**fn get_count_item(s: &str) -> (u64, &str) { **
** let mut it = s.split(' '); **
** let (Some(count_str), Some(item)) = (it.next(), it.next()) else { **
** panic!("Can't segment count item pair: '{s}'"); **
** }; **


** let Ok(count) = u64::from_str(count_str) else { **
** panic!("Can't parse integer: '{count_str}'"); **
** }; **


** (count, item) **
**} **


**assert_eq!(get_count_item("3 chairs"), (3, "chairs")); **

이름 바인딩의 범위는 이를 match 또는 if let-else 표현과 다르게 만드는 주요 요소입니다. 이전에는 불행하게도 약간의 반복과 outer let를 사용하여 이러한 패턴을 흉내낼 수 있었습니다.

**let (count_str, item) = match (it.next(), it.next()) { **
** (Some(count_str), Some(item)) => (count_str, item), **
** _ => panic!("Can't segment count item pair: '{s}'"), **
**}; **


**let count = if let Ok(count) = u64::from_str(count_str) { **
** count **
**} else { **
** panic!("Can't parse integer: '{count_str}'"); **
**}; **



레이블 달린 블록의 break

이제는 일반 블록 표현식에 break의 타겟으로 라벨을 지정하여 해당 블록을 조기에 종료할 수 있습니다.

이건 goto 문처럼 보일 수도 있지만, 블록 내에서 끝까지 이동하는 임의의 점프가 아니에요.
이런건 루프 블록으로 이미 가능했죠.

레이블이 지정된 break로 항상 한 번만 실행되는 루프를 작성하는 사람들을 본 적이 있을 겁니다.

이제 그걸 위한 기능이 생겼어요!
레이블이 지정된 break에는 루프와 마찬가지로 표현식 값이 포함될 수 있으니, 다중 구문 블록이 이른 'return' 값을 가질 수 있습니다.

**let result = 'block: { **
** do_thing(); **


** if condition_not_met() { **
** break 'block 1; **
** } **


** do_next_thing(); **


** if condition_not_met() { **
** break 'block 2; **
** } **


** do_last_thing(); **


** 3******
**}; **




분할된 Linux debuginfo

Rust 1.51에서 컴파일러 팀은 macOS에서 분할된 디버그 정보에 대한 지원을 추가했고, 이제 이 옵션은 Linux에서도 안정적으로 사용할 수 있습니다.

-Csplit-debuginfo=unpacked는 debuginfo를 여러개의 .dwo DWARF 오브젝트 파일로 분할합니다.

-Csplit-debuginfo=packed는 모든 debuginfo가 함께 패키징된 출력 바이너리와 함께 단일 .dwp DWARF 패키지를 생성합니다.

-Csplit-debuginfo=off는 여전히 기본 동작이며, 여기에는 오브젝트 및 최종 바이너리의 .debug_* ELF 섹션에 DWARF 데이터가 포함됩니다.

Split DWARF를 사용하면 링커가 debuginfo 처리를 피할 수 있으므로(더 이상 링크되는 개체 파일에 없기 때문에) 링크 시간을 단축할 수 있습니다!

이제 다른 타겟도 플랫폼별 기본값을 사용하여 stable 옵션으로 -Csplit-debuginfo를 허용하지만, 다른 값을 지정하는 것은 여전히 unstable입니다.




Stable이 된 API

다음 메서드와 트레잇 정의는 이제 stable입니다.

std::backtrace::Backtrace
Bound::as_ref
std::io::read_to_string
<*const T>::cast_mut
<*mut T>::cast_const

여기서 특히 Backtrace API를 사용하면, 일반적으로 패닉 backtrace를 제공하는 동일한 플랫폼별 구현을 사용하여 언제든지 스택 backtrace를 캡처할 수 있습니다.
이는 오류 타입에 런타임 컨텍스트를 추가하는 데 유용할 수 있어요.

다음 API는 이제 const 컨텍스트에서 사용가능합니다.

<*const T>::offset_from
<*mut T>::offset_from




호환성 노트

RLS 지원 중단의 마지막 단계로, 이 릴리스에서는 RLS를 지원 중단 경고를 표시하는 소형 LSP 서버로 교체하여 사용자에게 Rust-analyzer로 마이그레이션할 것을 권장합니다.




기타 변경점

1.65 릴리즈에는 이외의 기타 변경점들도 있습니다.

이제 최적화된 컴파일을 위해 MIR 인라이닝이 활성화됩니다. 이건 실제 crate의 컴파일 시간을 3-10% 향상시킵니다.

빌드를 스케줄링할 때 Cargo는 이제 성능을 개선하기 위해 pending인 작업의 큐를 정렬합니다.

그리고 RustCargoClippy에서 무엇이 바뀌었는지 확인해보세요.




1.65.0의 컨트리뷰터들

1.65의 완성엔 수많은 사람들이 함께했습니다. 전부 여러분이 없었다면 불가능했을 거에요.
고마워요!