# Rust 1.96.0 발표

> Clean Markdown view of GeekNews topic #29993. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=29993](https://news.hada.io/topic?id=29993)
- GeekNews Markdown: [https://news.hada.io/topic/29993.md](https://news.hada.io/topic/29993.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-05-30T03:02:13+09:00
- Updated: 2026-05-30T03:02:13+09:00
- Original source: [blog.rust-lang.org](https://blog.rust-lang.org/2026/05/28/Rust-1.96.0/)
- Points: 2
- Comments: 1

## Topic Body

- **Rust 1.96.0**은 `rustup update stable`로 설치할 수 있으며, 향후 릴리스 검증은 beta/nightly 채널에서 참여 가능함
- 새 `core::range::Range*` 타입은 `Iterator` 대신 **IntoIterator**를 구현해 `Copy` 구현이 가능하며, 향후 범위 문법의 기본 타입이 될 예정임
- **assert_matches!** 와 `debug_assert_matches!`는 패턴 불일치 시 값의 `Debug` 표현을 함께 출력해 테스트 실패 진단을 쉽게 만듦
- WebAssembly 대상은 더 이상 `--allow-undefined`를 기본 전달하지 않아 **정의되지 않은 심볼**이 import가 아니라 링커 오류가 됨
- Cargo에는 서드파티 레지스트리 사용자를 위한 **CVE-2026-5223**과 `CVE-2026-5222` 수정이 포함됐고, crates.io 사용자는 영향받지 않음

---

### Rust 1.96.0 주요 변경점
- ## 업데이트와 테스트 채널
  - 기존 Rust를 `rustup`으로 설치한 사용자는 `rustup update stable`로 **Rust 1.96.0**을 받을 수 있음
  - `rustup`이 없으면 Rust 웹사이트의 [`rustup` 설치 페이지](https://www.rust-lang.org/install.html)에서 설치할 수 있으며, [`1.96.0 상세 릴리스 노트`](https://doc.rust-lang.org/stable/releases.html#version-1960-2026-05-28)도 공개됨
  - 향후 릴리스 검증에 참여하려면 `rustup default beta` 또는 `rustup default nightly`로 **beta/nightly 채널**을 사용할 수 있고, 버그는 [Rust 이슈 트래커](https://github.com/rust-lang/rust/issues/new/choose)에 보고 가능함
- ## 새로운 `Range*` 타입
  - 기존 `Range`와 관련 `core::ops` 타입은 많은 사용자가 `Copy`를 기대하지만, 직접 `Iterator`를 구현하기 때문에 `Copy`를 함께 구현하지 않았음
  - 같은 타입에 `Iterator`와 `Copy`를 함께 구현하는 방식은 [Clippy가 지적하는 footgun](https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#copy_iterator)이어서 피하고 있었음
  - [RFC3550](https://rust-lang.github.io/rfcs/3550-new-range.html)은 `Iterator` 대신 `IntoIterator`를 구현하는 대체 범위 타입을 제안했고, 이 구조에서는 해당 타입들이 `Copy`도 구현할 수 있음
  - 표준 라이브러리에는 `core::range::Range`, `core::range::RangeFrom`, `core::range::RangeInclusive`와 관련 **반복자**들이 안정화됨
  - 가까운 향후 Rust 버전에는 `core::ops`에서 다시 내보내는 `core::range::RangeFull`과 `core::range::RangeTo`, 현재 범위 타입의 새 위치가 될 `core::range::legacy::*`도 추가될 예정임
  - `0..1` 같은 **범위 문법**은 현재 레거시 타입을 만들지만, 향후 에디션에서 `core::range` 타입으로 바뀔 예정임
  - 새 안정화로 `start`와 `end`를 분리하지 않고도 슬라이스 접근자를 `Copy` 타입에 저장할 수 있음
  - 예시:
    ```rust
    use core::range::Range;
    
    #[derive(Clone, Copy)]
    pub struct Span(Range&lt;usize&gt;);
    
    impl Span {
        pub fn of(self, s: &str) -> &str {
            &s[self.0]
        }
    }
    ```
  - 새 `RangeInclusive`는 필드를 공개하며, 레거시 버전처럼 소진된 반복자 상태 노출을 피할 필요가 없음
  - 새 타입은 반복을 시작하려면 먼저 변환되어야 하므로 공개 필드가 문제가 되지 않음
  - 라이브러리 작성자는 공개 API에서 레거시와 새 범위 타입을 모두 받는 `impl RangeBounds` 사용을 고려해야 함
  - 구체 타입이 필요하면 향후 기본값이 될 **새 범위 타입**을 선호하는 것이 권장됨
- ## 패턴 매칭 단언 매크로
  - 새 매크로 [`assert_matches!`](https://doc.rust-lang.org/stable/std/macro.assert_matches.html)와 [`debug_assert_matches!`](https://doc.rust-lang.org/stable/std/macro.debug_assert_matches.html)는 값이 주어진 패턴과 맞는지 검사하고, 맞지 않으면 해당 값의 `Debug` 표현과 함께 패닉함
  - 두 매크로는 본질적으로 `assert!(matches!(..))`, `debug_assert!(matches!(..))`와 같지만, 실패 시 출력되는 값 덕분에 **진단 가능성**이 좋아짐
  - 같은 이름의 매크로를 제공하는 인기 서드파티 크레이트와 충돌할 수 있어 표준 프렐류드에는 추가되지 않았음
  - 사용 전 `core` 또는 `std`에서 직접 가져와야 함
  - 예시:
    ```rust
    use core::assert_matches;
    
    /// [Random Number](https://xkcd.com/221/)
    fn get_random_number() -> u32 {
        // chosen by a fair dice roll.
        // guaranteed to be random.
        4
    }
    
    fn main() {
        assert_matches!(get_random_number(), 1..=6);
    }
    ```
- ## WebAssembly 대상 변경
  - WebAssembly 대상은 더 이상 링커에 `--allow-undefined`를 전달하지 않음
  - 링크 시 **정의되지 않은 심볼**은 `"env"` 모듈의 WebAssembly import로 변환되지 않고 링커 오류가 됨
  - 링크 관련 심볼이 모두 정의되지 않으면 모듈이 링크되지 않으므로, 버그를 더 일찍 잡고 심볼 이름 등에서 발생하는 우발적 문제를 막을 수 있음
  - 정의되지 않은 링크 관련 심볼은 보통 빌드 시간 버그나 설정 오류를 나타냄
  - 기존 동작이 의도된 경우 `RUSTFLAGS=-Clink-arg=--allow-undefined`로 되돌리거나, 소스 코드에서 심볼을 정의하는 블록에 `#[link(wasm_import_module = "env")]`를 사용할 수 있음
  - 이 변경은 [이전 블로그 공지](https://blog.rust-lang.org/2026/04/04/changes-to-webassembly-targets-and-handling-undefined-symbols/) 이후 Rust 1.96에서 적용됨

### 안정화 API와 보안 수정
- ## 안정화된 API
  - [`assert_matches!`](https://doc.rust-lang.org/stable/std/macro.assert_matches.html)
  - [`debug_assert_matches!`](https://doc.rust-lang.org/stable/std/macro.debug_assert_matches.html)
  - [`From&lt;T&gt; for AssertUnwindSafe&lt;T&gt;`](https://doc.rust-lang.org/stable/std/panic/struct.AssertUnwindSafe.html#impl-From%3CT%3E-for-AssertUnwindSafe%3CT%3E)
  - [`From&lt;T&gt; for LazyCell<T, F>`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#impl-From%3CT%3E-for-LazyCell%3CT,+F%3E)
  - [`From&lt;T&gt; for LazyLock<T, F>`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#impl-From%3CT%3E-for-LazyLock%3CT,+F%3E)
  - [`core::range::RangeToInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeToInclusive.html)
  - [`core::range::RangeToInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeToInclusiveIter.html)
  - [`core::range::RangeFrom`](https://doc.rust-lang.org/stable/core/ops/struct.RangeFrom.html)
  - [`core::range::RangeFromIter`](https://doc.rust-lang.org/stable/core/ops/struct.RangeFromIter.html)
  - [`core::range::Range`](https://doc.rust-lang.org/stable/std/range/struct.Range.html)
  - [`core::range::RangeIter`](https://doc.rust-lang.org/stable/std/range/struct.RangeIter.html)
- ## Cargo 보안 권고 2건
  - Rust 1.96은 서드파티 레지스트리 사용자를 위한 **Cargo 취약점 2건**의 수정 사항을 포함함
  - [CVE-2026-5223](https://blog.rust-lang.org/2026/05/25/cve-2026-5223/)은 심볼릭 링크가 있는 크레이트 tarball 추출과 관련된 **중간 심각도** 취약점임
  - [CVE-2026-5222](https://blog.rust-lang.org/2026/05/25/cve-2026-5222/)는 정규화된 URL을 통한 인증과 관련된 **낮은 심각도** 취약점임
  - crates.io 사용자는 두 취약점 모두의 영향을 받지 않음
- ## 추가 변경 사항
  - [Rust 1.96.0 변경 사항](https://github.com/rust-lang/rust/releases/tag/1.96.0)
  - [Cargo 1.96 변경 사항](https://doc.rust-lang.org/nightly/cargo/CHANGELOG.html#cargo-196-2026-05-28)
  - [Clippy 변경 사항](https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-196)

## Comments



### Comment 58582

- Author: neo
- Created: 2026-05-30T03:02:14+09:00
- Points: 1

###### [Lobste.rs 의견들](https://lobste.rs/s/4jgpkn/announcing_rust_1_96_0) 
* `assert_matches`는 계속 갖고 싶어지는데, 그때마다 새 크레이트를 추가할지 직접 다시 구현할지 고민하게 됨  
  그래서 **표준 라이브러리**에 들어가는 건 반가움
  * 테스트에서 괄호 쌍 수백 개를 지울 수 있다는 게 기대되는 게 이상한가? 전혀 아니라고 봄

* 범위를 **`Copy` 타입**으로 만들려는 단계가 마음에 듦  
  가끔 범위를 복제해야 해서 놀란 적이 있었고, `12..34`는 작고 복사 가능한 데이터여야 한다는 직관에도 더 잘 맞음  
  다만 같은 이름의 타입이 여러 개 생기면, VS Code가 다음에 `use` 선언을 자동 추가할 때 잘못된 타입을 가져올까 봐 조금 걱정됨  
  > A Rust version in the near future will also add [...] `core::range::legacy::*` as the new home for the current ranges. Range syntax like `0..1` still produces the legacy types for now, but will be updated to `core::range` types in a future edition.  
  Rust의 **에디션 시스템**이 꽤 좋은 아이디어처럼 보임
  * 알기로는 가져오기에서 모호성이 생기면 VS Code의 코드 액션이 어떤 걸 쓸지 고르는 **드롭다운**을 열어줘야 함
  * 이런 타입을 평소에 자주 가져올 필요는 없지 않나 싶음  
    대부분 사용자에게는 새 타입의 이점이 작아서 그냥 기존 타입을 계속 쓰면 되고, 다음 에디션 경계에서 새 타입이 자동으로 쓰이게 됨  
    명시적으로 두 버전을 모두 지원하려는 라이브러리 작성자들이 주로 타입을 가져오게 될 것 같음

* > These new macros have not been added to the standard prelude, because they would collide with popular third-party crates that provide macros with the same name. Instead, they should be manually imported from core or std before use.  
  이건 좀 이상하게 느껴짐  
  나중에 바꿀 계획이 있는 걸까? 생태계가 옮겨간 뒤, 예를 들어 3년쯤 지나 **작은 정리**로 바꾸고 싶은 종류의 일처럼 보임
  * 이런 부분에서 **에디션**이 도움이 됨  
    기존 프로젝트를 깨지 않고도 프렐류드를 바꿀 수 있음
