[Rust] 1.85.0 업데이트 발표 (번역)
https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html
러스트는 누구든 믿음직하고 효과적인 소프트웨어를 만들 수 있게 도와주는 끝내주는 언어입니다.
만약 rustup을 통해서 Rust의 이전버전을 설치해놓은 상대라면, 업데이트는 아주 쉽습니다. 그냥 이렇게 치면 돼요.
rustup update stable
rustup을 설치한 적이 없다면, 우리 웹사이트의 설치 페이지에서 받을 수 있습니다. 그리고 깃허브에서 이번 버전에 대한 릴리즈 노트를 참조해보세요.
미래의 릴리즈를 테스트해서 러스트 팀을 돕고 싶다면, 로컬에서 베타 채널(rustup default beta) 또는 nightly 채널(rustup default nightly)로 업데이트하는 것을 고려할 수 있습니다.
버그를 발견했다면 리포트해주세요!
1.85.0 stable엔 무엇이 있나요?
Rust 2024
에디션은 backwards 호환성 위험이 발생할 수도 있는 opt-in 변경을 위한 메커니즘입니다.
이를 달성하는 방법과 마이그레이션에 대한 자세한 지침은 에디션 가이드를 참조해주세요.
이건 우리가 출시한 것 중 가장 큰 에디션입니다.
에디션 가이드에 각 변경 사항에 대한 자세한 정보가 포함되어 있지만, 요약하자면 다음과 같습니다.
Language
RPIT lifetime capture rules —
use<..>이 없을 때 impl Trait 타입으로 된 파라미터의 default capture을 변경한다.
if let temporary scope —
if let 표현식에 대한 임시값(temporaries)들의 scope를 변경합니다.
Tail expression temporary scope —
블록에서 tail expression에 대한 임시값 스코프를 변경합니다.
Match ergonomics reservations —
혼란을 피하고 향후 개선을 허용하기 위해 일부 패턴 조합을 허용하지 않습니다.
Unsafe extern blocks —
extern block은 이제 unsafe 키워드를 필요로 합니다.
Unsafe attributes —
export_name, link_section, no_mangle attribute는 이제 unsafe로 표시되어야 합니다.
unsafe_op_in_unsafe_fn warning —
unsafe_op_in_unsafe_fn 린트는 이제 기본적으로 경고를 던지고, unsafe 함수에서 명시적인 unsafe {} 블록을 요구합니다.
Disallow references to static mut —
static mut 항목에 대한 참조는 이제 deny-by-default 오류를 생성합니다.
Never type fallback change —
never type ! coerce가 변경되며 never_type_fallback_flowing_into_unsafe의 lint level을 "deny"로 변경합니다.
Macro fragment specifiers —
macro_rules! 매크로에서의 expr macro fragment specifier는 이제 const 및 _ 표현과도 일치합니다.
Missing macro fragment specifiers —
missing_fragment_specifier lint는 이제 하드 오류가 되고, fragment specifier kind 없는 매크로 meta variable을 거부합니다.
gen keyword —
향후 제너레이터 블록 추가를 기대하며 gen 키워드를 예약합니다.
Reserved syntax —
guarded 문자열 리터럴이 향후 파싱될 수 있는 방식을 변경할 것으로 예상하며 #"foo"# 스타일 문자열 및 ## 토큰을 예약합니다.
Standard library
Changes to the prelude —
prelude에 Future와 IntoFuture 추가
Add IntoIterator for Box<[T]> —
Iterator가 boxed slice로도 동작할 수 있게 변경
Newly unsafe functions —
std::env::set_var, std::env::remove_var, std::os::unix::process::CommandExt::before_exec가 이제 unsafe functions이 됩니다.
Cargo
Cargo: Rust-version aware resolver —
rust-version 필드를 고려하도록 디폴트 dependency resolver의 동작을 변경합니다.
Cargo: Table and key name consistency —
몇가지 outdate된 Cargo.toml 키를 제거합니다.
Cargo: Reject unused inherited default-features —
default-features = false이 상속된 workspace dependency와 함께 작동하는 방식을 변경합니다.
Rustdoc
Rustdoc combined tests —
이제 Doctests가 단일 실행파일로 결합되어 성능이 크게 향상됩니다.
Rustdoc nested include! change —
중첩된 include! 파일의 상대 경로 동작이 변경됩니다.
Rustfmt
Rustfmt: Style edition —
이번 러스트 에디션부터 formatting 에디션을 독립적으로 제어할 수 있는 "스타일 에디션"의 개념을 소개합니다.
Rustfmt: Formatting fixes —
다양한 상황을 포매팅하는 것에 대해 많은 수정 사항이 있습니다.
Rustfmt: Raw identifier sorting —
r#foo 식별자도 이제 정렬되도록 변경합니다.
**Rustfmt: Version sorting — **
정수를 포함한 식별자를 정렬하는 방법을 변경합니다.
2024로 마이그레이션
이 가이드는 모든 새 기능에 대한 마이그레이션 지침을 포함하며, 일반적으로 기존 프로젝트를 새로운 에디션으로 전환하는 것을 고려합니다.
많은 경우에 cargo fix가 필요한 변경을 자동으로 처리할 수 있습니다.
아마 2024에는 코드 변경이 필요하지 않다는 것을 알 수 있을 겁니다!
cargo fix를 통한 자동 수정은 코드의 의미를 변경하지 않기 위해 매우 보수적으로 동작합니다.
많은 경우엔 코드를 동일하게 유지하면서도 새로운 2024의 시맨틱을 사용하기를 원할 수 있습니다.
예를 들어, expr 매크로 matcher를 계속 사용하면서도 새로운 2024의 drop order semantics을 원해서 conditional 전환을 무시하는 것입니다.
cargo fix의 결과는 추천으로 간주되어서는 안 되며, 행동을 유지하는 보수적인 전환일 뿐입니다.
많은 사람들이 이 에디션을 만들기 위해 함께했습니다. 고생하셨어요!
async closures
Rust는 이제 async || {}와 같은 비동기 클로저를 지원하며, 이는 호출될 때 future를 반환합니다.
이건 일반적인 클로저처럼 local 환경에서 값을 캡처할 수도 있는 async fn처럼 작동합니다.
이건 또한 표준 라이브러리 prelude에 있는 세 가지와 유사한 trait, AsyncFn, AsyncFnMut, AsyncFnOnce를 함께 제공합니다.
어떤 경우에는 이미 || async {}와 같은 일반적인 클로저+비동기 블록으로 근사하게 처리할 수 있습니다.
하지만 이런 내부 블록에 의해 반환된 Future는 클로저 캡처에서 borrow를 할 수 없습니다. async 클로저는 가능합니다.
**let mut vec: Vec
**let closure = async || { vec.push(ready(String::from("")).await); }; **
과거엔 Fn trait이 Future를 반환하는 higher-ranked 함수 시그너처를 적절하게 표현하는 것이 불가능했지만 이제는 AsyncFn trait으로 이를 작성할 수 있습니다.
**use core::future::Future; **
**async fn f
**{ todo!() } **
**async fn f2(_: impl for<'a> AsyncFn(&'a u8)) { todo!() } **
**async fn main() **
**{ **
** async fn g(_: &u8) { todo!() } **
** f(g).await; //^ ERROR mismatched types **| ERROR one type is more general than ****the other ******
** //
** f2(g).await; ****// ok! ******
**} **
따라서 async 클로저는 이 두 가지 문제에 대한 퍼스트클래스 솔루션을 제공합니다!
자세한 내용은 RFC 3668 및 안정화 report를 참조해주세요
diagnostics에서 trait 구현 숨기기
새로운 attribute #[diagnostic::do_not_recommend]는 진단 메시지의 일부로서, 임의의 trait 구현을 보여주지 않도록 컴파일러에 힌트를 주는 것입니다.
라이브러리 작성자가 컴파일러에게 도움이 되지 않거나 오해의 소지가 있는 제안을 하지 않도록 당부하는 방법이죠.
예를 들면, 이런겁니다.
pub trait Foo {}
pub trait Bar {}
impl<T: Foo> Bar for T {}
struct MyType;
fn main() {
** let _object: &dyn Bar = &MyType;**
}
error[E0277]: the trait bound MyType: Bar is not satisfied****
** --> src/main.rs:9:29
** |
9 | let _object: &dyn Bar = &MyType;
** | ^^^^ the trait Foo is not implemented for MyType**
** |**
note: required for MyType to implement Bar
** --> src/main.rs:4:14**
** |**
4 | impl<T: Foo> Bar for T {}
** | --- ^^^ ^**
** | |**
** | unsatisfied trait bound introduced here**
** = note: required for the cast from &MyType to &dyn Bar**
일부 API의 경우 Foo를 구현하고 그 blanket 구현을 통해 간접적으로 Bar를 얻는 것이 좋을 수 있습니다.
하지만 다른 경우에는, 대부분의 사용자가 Bar를 직접 구현해야 하니 Foo 제안은 도움도 안되는 잔소리일 겁니다.
그럴 때 진단 힌트를 추가하면 오류 메시지가 이렇게 변경됩니다.
#[diagnostic::do_not_recommend]
impl<T: Foo> Bar for T {}
error[E0277]: the trait bound MyType: Bar is not satisfied
** --> src/main.rs:10:29**
** |**
10 | let _object: &dyn Bar = &MyType;
** | ^^^^ the trait Bar is not implemented for MyType**
** |**
** = note: required for the cast from &MyType to &dyn Bar**
원래의 동기는 RFC 2397을 참조, 자세한 내용은 현재를 참조해주세요.
튜플을 위한 FromIterator와 Extend
Rust의 이전 버전에서는 (T, U) 튜플 쌍의 반복자에 대해서 Iterator::unzip과 같이 동작하도록 편의를 위한 trait을 구현했었습니다.
extend은 1.56, FromIterator는 1.79입니다.
이건 이제 싱글톤(T,)에서 12개 항목 길이(T1, T2, ..., T11, T12)까지 더 많은 튜플 버전으로 확장되었습니다.
예를 들어, 이제 collect()를 사용하여 한 번에 여러 컬렉션으로 팬아웃할 수 있습니다.
**use std::collections::{LinkedList, VecDeque}; **
**fn main() { **
** let (squares, cubes, tesseracts): (Vec<>, VecDeque<>, LinkedList<_>) = (0i32..10).map(|i| (i * i, i.pow(3), i.pow(4))).collect(); **
** println!("{squares:?}"); **
** println!("{cubes:?}"); **
** println!("{tesseracts:?}"); **
**} **
**[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] **
**[0, 1, 8, 27, 64, 125, 216, 343, 512, 729] **
**[0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561] **
std::env::home_dir() 수정
std::env::home_dir()는 몇년 동안 deprecate되었습니다. HOME 환경 변수가 설정되면(윈도에서 정상적인 구성이 아님) 일부 윈도우즈 구성에서 놀라운 결과를 제공할 수 있기 때문입니다.
우리는 이전에 이 비표준 구성을 염두하고 코드와의 호환성을 우려해서 동작 변경을 피했습니다.
이 함수도 꽤 오랫동안 deprecation이 되었으니, 이제 버그 해결을 위해 동작을 수정하고 있습니다.
그리고 후속 릴리즈를 통해 이 함수의 deprecation을 제거할 겁니다.
안정화된 API
BuildHasherDefault::new
ptr::fn_addr_eq
io::ErrorKind::QuotaExceeded
io::ErrorKind::CrossesDevices
{float}::midpoint
Unsigned {integer}::midpoint
NonZeroU*::midpoint
impl std::iter::Extend for tuples with arity 1 through 12
FromIterator<(A, ...)> for tuples with arity 1 through 12
std::task::Waker::noop
다음 API들은 이제 const context 버전도 stable입니다.
mem::size_of_val
mem::align_of_val
Layout::for_value
Layout::align_to
Layout::pad_to_align
Layout::extend
Layout::array
std::mem::swap
std::ptr::swap
NonNull::new
HashMap::with_hasher
HashSet::with_hasher
BuildHasherDefault::new
MaybeUninit::write
기타 변경점
이외의 모든 변경사항은 각각 Rust, Cargo, Clippy에서 확인하세요.
1.85.0의 컨트리뷰터들에게
1.85.0의 완성엔 수많은 사람들이 함께했습니다. 전부 여러분이 없었다면 불가능했을 거에요.