Rust Features in the Future
There are several Rust features that kernel developers have been hoping to
以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。
There are several Rust features that kernel developers have been hoping to stabilize, but Josh Triplett wanted to describe all of the other features that the Rust project is currently working on. He spoke about the topic at Kangrejos 2026, leaving the assembled kernel developers with several ideas about how to use these upcoming Rust features in the kernel. The features included refinements to the type system, small syntax improvements, and a smarter borrow checker.
Triplett began by cautioning that these features were works in progress, some more than others. "That means that you have more opportunity to shape how things work out," he said. He encouraged anyone interested in working on or further developing the features to get in touch with him. Even just letting the Rust developers know which features would solve a real problem in the kernel would help with prioritization.
The first feature that he wanted to highlight was
view types: a way to borrow only part of a structure. The borrow checker forbids having both a mutable reference and any other references to a structure at the same time, with one exception: within the body of a function, it is able to notice when a mutable reference is only used to access a subset of the fields of a structure. In that case, the other fields can be non-mutably referenced without causing a borrow-checking error. The problem with that is that it makes it hard to break up complicated functions into smaller pieces, because that would require the borrow checker to reason about per-field access across multiple functions, which it cannot do.
This is a real frustration that people have with the language, Triplett said. It almost caused him to bounce off of Rust when he first encountered it. View types provide a solution, by allowing a function's signature to declare exactly which fields of a structure it touches. The syntax for doing so is still to be decided; the current work is focused on making it work with the type system.
Miguel Ojeda said that the kernel would probably want view types, but hadn't requested it explicitly because it was already on the roadmap at that point. Andreas Hindborg asked what the expected time frame for view types was. Jana Dönszelmann said that there was currently only one person working on it, but that they were trying to obtain funding to make it a full-time effort. She guessed that prototypes of the feature would be available in the next year.
The next feature that Triplett wanted to discuss was also an extension to the type system.
Pattern types are an additional way to encode program invariants using the type system. In many ways, it is a generalization of Rust's existing
NonZero and
NonNull types. A pattern type allows the programmer to say that a value has a particular type and, in addition, matches some pattern. For example, a valid error number could be restricted to fall between zero and 4096, while still having the layout and ABI behavior of a u32.
type Errno = u32 is 0..4096;
This is not an unprecedented feature, although it is not particularly common.
Ada and
LiquidHaskell both offer the same kind of refinement as part of the type system. Rust's implementation is available in nightly versions of the language, but it hasn't been integrated into the standard library, and probably needs some help to be made properly useful.
Kent Overstreet asked whether the current syntax for pattern types would be flexible enough to accommodate alignment niches if they are eventually added. Triplett said that he did not have an exact syntax in mind for alignment patterns, but that any syntax for patterns that is added to the language would work with pattern types. He suggested that adding patterns for matching certain bit layouts was probably the right approach.
Alastair Francis wanted to know whether operations on pattern types involved run-time checks. If one defines a nanosecond type, and it goes over one billion, what happens? Just because u32 implements Add, Triplett said, does not mean that u32 is 0..1_000_000_000 implements Add. The compiler treats them as distinct types. So, practically, one cannot add anything to a pattern type without first coercing it to the more general integer type. Converting a normal integer back to a pattern-refined integer requires an explicit check, so the programmer will have to handle the error case.
A much bigger potential change to the type system is the introduction of either
linear types or
unforgettable types, two closely related ideas that are still in the speculative planning stage. The core concept behind both is that it should be possible to create types that are impossible to implicitly drop. That is as far as linear types go, but unforgettable types would also forbid leaking memory containing them using std::mem::forget(). This would allow programmers to make types representing a database transaction, for example, that must be committed or aborted instead of forgotten about. "It sounds like it should be easy," Triplett said, but the feature turns out to pose complications for other parts of the language.
For example, panicking with an unforgettable type on the stack is unsafe, so the language needs some way to ensure that a section of code can't panic. That was once blocked on some improvements to the trait solver, but work on the new trait solver is progressing again. Triplett thought this feature was probably useful for the kernel, which Ojeda agreed with.
Moving away from type-system details, Triplett brought up the problem of using Rust's
turbofish operator (::<>) on
Into::into(), which is used to infallibly convert from one type to another, when that is possible. When calling a method that takes a generic type parameter, the programmer can specify the parameter explicitly by writing ::<SomeType>. That syntax is referred to as a "turbofish" as a tongue-in-cheek reference to the way that it looks a bit like a fish with a big tail.
The problem is that one of the most common situations in which one might want to specify a type explicitly is when converting from one type to another using the Into trait. Unfortunately, that trait is not written correctly to allow the turbofish operator to be used. The turbofish only works to specify type arguments that are passed to a given function or method; into() has no type arguments, instead relying on the generic type arguments of the trait that it is defined in, Into.
There is a clever fix for this that only involves changes to the standard library, Triplett said. The library team is hoping to make the change in the next Rust edition. Gary Guo asked about a few alternative approaches, such as
type ascription. Triplett explained that they had tried many of those, but found the solutions less straightforward than they seemed.
Another improvement to the language's usability is a proposed infix
pattern-matching operator. Rust has some support for pattern matching inside conditionals, but that can result in having to read the condition in an awkward order, Triplett explained. For example, this code matches the pattern Some(x) against the result of func().await, and then continues with the rest of the conditional, requiring the programmer to scan back and forth in order to read it:
while let Some(x) = func().await && x.some_condition() { ... }
Adding inline pattern matching would let programmers write everything from left to right, and eliminate a lot of small helper functions such as .is_none() in favor of a single consistent syntax:
while func().await is Some(x) && x.some_condition() { ... }
The proposed operator would work in any place that expects a boolean. There is an ongoing language experiment to try the concept out, but a future edition of Rust will be needed to change the syntax, since the parsing is not backward compatible. Tomáš Šedovič asked whether that meant the
matches!() macro would no longer be useful. Triplett said that it would be kept for backward compatibility, but agreed it would see less use.
Guo asked whether the new syntax would be transformed inside the compiler to something like the current if let or while let syntax. Triplett said no — the new operator works in more contexts, so it will be transformed to a construct that is legal in any location that expects a boolean. Guo asked where the bindings introduced by the pattern would be in scope. "Anywhere you can be sure that the result is true," Triplett said. Some people have discussed using patterns to bind two values to the same variable, but that is not yet planned. Guo remarked that the new operator sounded like a general postfix match, which Triplett agreed with.
Triplett was excited for this feature because he believes it will reduce the number of helper functions that an average language-learner will need to understand; instead, they can learn this single feature and use it everywhere, which makes the language more consistent and easy to learn. The Rust developers can't always simplify the language like that, Triplett said, but it's good when they can.
Another feature that should make the language easier to learn is
Polonius, the new borrow checker. In Rust 1.0, scope was decided entirely lexically: everything lived until the end of the block in which it was declared. That turned out to be unintuitive, so a rewrite of the borrow checker introduced non-lexical lifetimes, where a lifetime can end just after the last reference to a variable, instead of at the end of the scope.
That helps some, but there are still situations where the borrow checker will reject a program that any human can tell is valid. This comes up particularly often in the context of loops, but can occur anywhere that control flow influences which references are effectively no longer used. For example, returning from the middle of a loop can confuse the current borrow checker about whether a reference is retained in the next loop iteration.
Polonius fixes that problem, by tracking how borrowing interacts with the flow of control. It is still not perfect, but it "fixes a lot of things that made people say 'Wait, that didn't work before?', which we love," Triplett said. Polonius has been in development for years, but it is finally enabled on nightly versions of the compiler. The main work needed to stabilize it is eliminating a few performance regressions.
Triplett asked whether the kernel had been tested with Polonius, and Ojeda said that it was tested with both stable and nightly versions of the compiler, so the kernel should work fine with Polonius. It probably can't be turned on unconditionally for all kernel code until the minimum supported Rust version is increased, however, since the version in older compilers has bugs that have since been fixed.
A more complex potential feature is
compile-time execution, inspired by
Zig's comptime. Rust's existing const functions can run at either compile time or run time, Triplett explained. That is convenient, but it means that they cannot access compiler APIs that don't exist at run time. If there were a new type of function that was only allowed to run at compile time, the language could add a compile-time reflection API.
Ojeda asked whether comptime functions were like const evaluation in C++. Triplett said that it was similar, but that the Rust team was taking more inspiration from Zig. Overstreet asked whether this would make Rust compilation a multi-phase process, as it is in other languages with rich macro systems, such as Scheme. There is a plan in place to handle that, Triplett said. The Rust compiler already uses a
query-based system that should support arbitrary phases in theory, but the prototype comptime functions would avoid adding too much complexity for the first few versions.
Once comptime functions are available, that would open up the possibility of a new macro system. Rather than needing to write
procedural macros as part of a separate crate, macros could potentially be implement
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。