#assert #const-generics #static #expression

static_assert_generic

涉及const和类型泛型的静态断言

3个版本

新增 0.1.2 2024年8月24日
0.1.1 2024年6月7日
0.1.0 2024年5月2日

进程宏中排名第932

Download history 143/week @ 2024-04-27 16/week @ 2024-05-04 9/week @ 2024-05-18 11/week @ 2024-05-25 90/week @ 2024-06-01 35/week @ 2024-06-08 3/week @ 2024-06-15 4/week @ 2024-06-29

每月下载量200
用于non_empty_continuous

0BSD许可证

20KB
120

由于Rust 1.79的发布,该crate已经过时,因为1.79添加了内联const表达式

fn foo<const N: usize>() {
    const { assert!(N > 30); }
}

其他版本尚未撤回,因为它们仍然按预期工作。

许可证:0BSD


lib.rs:

在编译时断言语句的功能,包括使用const和类型泛型的语句。

它通过尝试评估一个常量并失败(通过编译时恐慌)来实现,如果表达式评估为假。由于cargo check不评估常量,因此带有指定泛型的static_assert!不会显示为错误,并且需要完整的cargo build编译。这是一种相当“黑客式”的断言方法,因此我不太惊讶如果Rust的将来版本会破坏它。目前,它仍然在1.77.2版本中正常工作。

已经在static_assert crate中尝试添加const泛型功能,但似乎不会很快添加。

这些断言在任何函数签名或类型系统中都没有出现,这可能使得在创建任何类型的抽象时难以推理。您可能需要谨慎使用,并在使用时明确记录。

概述

静态断言根据泛型的值有条件地引发错误

fn foo<const N: usize>() {
static_assert!((N: usize) N != 0 => "N must be a non-zero value!");
// Some other functionality.
}

fn main() {
foo::<12>(); // compiles
foo::<0>(); // doesn't compile
}
// error[E0080]: evaluation of `foo::Assert::<0>::CHECK` failed
//  |         static_assert!((N: usize) N != 0 => "N must be a non-zero value!");
//  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'N must be a non-zero value!'
//
// note: the above error was encountered while instantiating `fn main::foo::<0>`
//  |     foo::<0>();

重要#1

静态断言失败(例如,在这种情况下 foo::<0>())在使用 cargo check 时不会显示错误。然而,尝试编译(使用 cargo build)仍然会显示错误,这是预期的。

重要 #2

未指定泛型常量的类型将导致 can't use generic parameters from outer item 错误

fn foo<const N: u32>() {
static_assert!((N) N != 0 => "N must be a non-zero value!");
// can't use generic parameters from outer item
}

这不是宏出问题,这只是错误信息误导。可以通过简单地指定类型(static_assert!((N: u32) N != 0))来修复。

重要 #3

未在表达式中声明泛型将导致错误。

fn bar<const N: usize>() {
static_assert!(() N != 0 => "N must be a non-zero value!");
// can't use generic parameters from outer item
}

重要 #4

如果传递了一个 ?Sized 的类型泛型,则会导致错误

fn foo<T: ?Sized>() {
static_assert!((T) ...);
// the associated item `CHECK` exists for struct `Assert<T>`, but its trait bounds were not satisfied
}

必须使用 ?static_assert!((T?) ...);)来指定可选大小泛型。

示例

断言常量表达式

static_assert!(() 1 + 2 < 17); // True statement, compiles.

static_assert!(() 45 * 25 < 3); // False statement, does not compile:

// error[E0080]: evaluation of constant value failed
//  |     static_assert!(() 45 * 25 < 3)
//  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'Static assert failed.'


可以可选地指定错误信息

static_assert!(() 45 * 25 < 3 => "This is the error message!");
// the evaluated program panicked at 'This is the error message!'


使用 identifier: type 语法传递泛型常量

fn foo<const C: u32>() {
static_assert!((C: u32) C > 3 => "C must be greater than 3!");
}


也可以使用类型泛型。

fn baz<T>() {
static_assert!((T) std::mem::size_of::<T>() == 4 => "T must be 4 bytes long!");
}


需要使用此语法传递无尺寸类型

fn baz<U: ?Sized>() {
static_assert!((U?) true => "There isn't much you can statically check about unsized types.");
}


可以同时使用多个泛型。

fn baz<const N: usize, const M: usize, T>() {
static_assert!((N: usize, M: usize) N > M => "N must be greater than M!");
static_assert!((N: usize, T) N == std::mem::size_of::<T>() / 2 => "N must be half the size of T!");
}

baz::<4, 7, u64>(); // panics at "N must be greater than M!"
baz::<4, 1, u8>(); // panics at "N must be half the size_of T!"

依赖项

~270–720KB
~17K SLoC