[Rust] 1.80.0 업데이트 발표 (번역)
https://blog.rust-lang.org/2024/07/25/Rust-1.80.0.html
러스트는 누구든 믿음직하고 효과적인 소프트웨어를 만들 수 있게 도와주는 끝내주는 언어입니다.
만약 rustup을 통해서 Rust의 이전버전을 설치해놓은 상대라면, 업데이트는 아주 쉽습니다. 그냥 이렇게 치면 돼요.
rustup update stable
rustup을 설치한 적이 없다면, 우리 웹사이트의 설치 페이지에서 받을 수 있습니다. 그리고 깃허브에서 이번 버전에 대한 릴리즈 노트를 참조해보세요.
미래의 릴리즈를 테스트해서 러스트 팀을 돕고 싶다면, 로컬에서 베타 채널(rustup default beta) 또는 nightly 채널(rustup default nightly)로 업데이트하는 것을 고려할 수 있습니다.
버그를 발견했다면 리포트해주세요!
1.80.0 stable에는 무엇이 있나요?
LazyCell와 LazyLock
이러한 "lazy" 타입은 데이터 초기화를 첫 번째 접근까지 지연시킵니다.
1.70에서 안정화된 OnceCell 및 OnceLock 타입과 유사하지만, 초기화 기능이 셀에 포함되어 있다는게 다릅니다.
이건 인기 있는 lazy_static 및 once_cell crate로부터 표준 라이브러리에 채택된 기능의 안정화를 완료합니다.
LazyLock은 thread-safe 옵션이며, static 값과 같은 곳에 적합합니다.
예를 들어, spawn 스레드와 메인 스코프 모두 아래에서 정확히 동일한 지속 시간을 볼 수 있습니다.
LAZY_TIME은 static에 먼저 접근하는 쪽에서 한 번 초기화되기 때문이죠.
그리고 OnceLock::get_or_init()과 달리 두 가지 모두 사용자 측에서 초기화하는 방법을 알 필요가 없습니다.
use std::sync::LazyLock;
use std::time::Instant;
static LAZY_TIME: LazyLock
fn main() {
** let start = Instant::now();**
** std:🧵:scope(|s| {**
** s.spawn(|| {**
** println!("Thread lazy time is {:?}", LAZY_TIME.duration_since(start));**
** });**
** println!("Main lazy time is {:?}", LAZY_TIME.duration_since(start));**
** });**
}
LazyCell은 스레드 동기화 없이 동일한 작업을 수행하므로 static에 필요한 Sync를 구현하지 않지만 스레드별 초기화임이 명확한 thread_local! static에서는 여전히 사용할 수 있습니다.
두 타입 모두 thread-safe 요구 사항에 따라 다른 데이터 구조에서도 사용할 수 있으므로, lazy 초기화는 어디에서나 사용할 수 있습니다!
Checked cfg의 names과 values
1.79에 rustc는 --check-cfg 플래그를 안정화했었죠.
이제 Cargo 1.80은 rustc에서 사전 정의된 값 외에도 알고 있는 모든 cfg 이름과 값에 대해서 이러한 검사를 가능하게 합니다.
여기에는 Cargo.toml의 feature name과 빌드 스크립트의 새 cargo::rustc-check-cfg 출력이 포함됩니다.
Unexpected cfgs는 오타나 기타 잘못된 구성을 잡기 위해 warn-by-default unexpected_cfgs lint에 의해 보고됩니다.
예를 들어, 선택적 rayon 의존성이 있는 프로젝트에서 이 코드는 잘못된 feature 값에 대해 구성됩니다.
fn main() {
** println!("Hello, world!");**
** #[cfg(feature = "crayon")]**
** rayon::join(**
** || println!("Hello, Thing One!"),**
** || println!("Hello, Thing Two!"),**
** );**
}
warning: unexpected cfg condition value: crayon
** --> src/main.rs:4:11**
** |**
4 | #[cfg(feature = "crayon")]
** | ^^^^^^^^^^--------**
** | |**
** | help: there is a expected value with a similar name: "rayon"**
** |**
** = note: expected values for feature are: rayon**
** = help: consider adding crayon as a feature in Cargo.toml**
** = note: see https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html for more information about checking conditional configuration**
** = note: #[warn(unexpected_cfgs)] on by default**
실제 rayon feature가 활성화되었는지 여부와 상관없이 동일한 경고가 보고됩니다.
Cargo.toml 매니페스트의 [lints] 테이블은 또한 커스텀 cfg에 대한 알려진 이름&값 목록을 확장하는 데 사용할 수 있습니다.
rustc는 경고에 사용할 구문을 자동으로 제공합니다.
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(foo, values("bar"))'] }
이 기능에 대한 자세한 내용은 nightly에서 기능을 사용할 수 있음을 알렸던 이전 게시물에서 확인할 수 있습니다.
패턴 표현에서의 Exclusive ranges
Rust의 range 패턴은 이제 Range 및 RangeTo 표현 타입과 유사하게 a..b 또는 ..b의 형태로 작성된 exclusive endpoint을 사용할 수 있습니다.
예를 들어, 다음 패턴은 이제 한 패턴의 끝과 다음 패턴의 시작에 대해 동일한 상수를 사용할 수 있습니다.
pub fn size_prefix(n: u32) -> &'static str {
** const K: u32 = 10u32.pow(3);**
** const M: u32 = 10u32.pow(6);**
** const G: u32 = 10u32.pow(9);**
** match n {**
** ..K => "",**
** K..M => "k",**
** M..G => "M",**
** G.. => "G",**
** }**
}
이전에는 패턴에서 inclusive(a..=b 나 ..=b) 또는 open(a..) 범위만 허용되었으므로, 이와 같은 코드는 inclusive endpoint를 위해 K - 1 같은 별도의 상수가 필요했습니다.
exclusive range는 오랫동안 unstable한 기능으로 구현되었지만, 혼란을 가중시키고 패턴에서 개별 오류의 가능성을 높일 수 있다는 blocking concern가 있었습니다.
이를 위해 패턴 매칭의 격차를 더 잘 감지할 수 있도록 exhaustiveness checking가 강화되었으며, 새로운 lint non_contiguous_range_endpoint와 overlapping_range_endpoints과 추가되었습니다.
이 새 lint들은 exclusive 패턴을 inclusive로 전환하거나 그 반대의 경우를 처리할 때 도움이 될 겁니다.
Stable이 된 API들
impl Default for Rc
impl Default for Rc
impl Default for Rc<[T]>
impl Default for Arc
impl Default for Arc
impl Default for Arc<[T]>
impl IntoIterator for Box<[T]>
impl FromIterator
impl FromIterator
LazyCell
LazyLock
Duration::div_duration_f32
Duration::div_duration_f64
Option::take_if
Seek::seek_relative
BinaryHeap::as_slice
NonNull::offset
NonNull::byte_offset
NonNull::add
NonNull::byte_add
NonNull::sub
NonNull::byte_sub
NonNull::offset_from
NonNull::byte_offset_from
NonNull::read
NonNull::read_volatile
NonNull::read_unaligned
NonNull::write
NonNull::write_volatile
NonNull::write_unaligned
NonNull::write_bytes
NonNull::copy_to
NonNull::copy_to_nonoverlapping
NonNull::copy_from
NonNull::copy_from_nonoverlapping
NonNull::replace
NonNull::swap
NonNull::drop_in_place
NonNull::align_offset
<[T]>::split_at_checked
<[T]>::split_at_mut_checked
str::split_at_checked
str::split_at_mut_checked
str::trim_ascii
str::trim_ascii_start
str::trim_ascii_end
<[u8]>::trim_ascii
<[u8]>::trim_ascii_start
<[u8]>::trim_ascii_end
Ipv4Addr::BITS
Ipv4Addr::to_bits
Ipv4Addr::from_bits
Ipv6Addr::BITS
Ipv6Addr::to_bits
Ipv6Addr::from_bits
Vec::<[T; N]>::into_flattened
<[[T; N]]>::as_flattened
<[[T; N]]>::as_flattened_mut
이 API들은 이제 const context에서도 stable입니다.
<[T]>::last_chunk
BinaryHeap::new
기타 변경점
이외의 모든 변경사항은 각각 Rust, Cargo, Clippy에서 확인하세요.
1.80.0의 컨트리뷰터들에게
1.80.0의 완성엔 수많은 사람들이 함께했습니다. 전부 여러분이 없었다면 불가능했을 거에요.