Shipping Const Generics in 2020

栏目: IT技术 · 发布时间: 4年前

内容简介:It’s hard to believe that its been more than 3 years since I openedFor those who don’t know,We’ve been using the const generics feature to

It’s hard to believe that its been more than 3 years since I opened RFC 2000 , which defined the const generics for Rust. At the same time, reading the RFC thread, there’s also been a huge amount of change in this area: for one thing, at the time the RFC was written, const fns weren’t stable, and consts weren’t even being evaluated using miri yet. There’s been a lot of work over the years on the const generics feature, but still nothing has shipped. However, I think we have defined a very useful subset of const generics which is stable enough to ship in the near term.

For those who don’t know, const generics refers to generics that are constant values, rather than types. This allows types to be parameterized by, for example, specific integer values. In stable Rust, only the special array type - [T; N] - has a const parameter (the length of the array), and there is no way to be abstract over all values of N , even for arrays. Const generics will allow creating new types parameterized by values, as well as implementing traits and functions that are abstract over those values. For example:

// This is a custom type which is parameterized by a `usize`
pub struct Foo<const N: usize>{ 
    bytes: [u8; N],
}


// This is a trait which has been implemented for arrays of
// any length.
impl<T: Debug, const N: usize> Debug for [T; N] {
}

We’ve been using the const generics feature to implement traits for arrays for over a year, artificially limiting the implementations to arrays of length 32. We are planning to lift that limitation on those impls in an upcoming release. By stabilizing const generics, we could start to allow external crates to implement traits for all arrays as well, and many other interesting use cases. There will be two important limitations, however.

Only integral primitive types for const generics

The initial types that a const generic can have will be limited to the integral primitive types. That means the signed and unsigned integer types, booleans, and chars. For now, no compound or user-defined types will be allowed, and no references (meaning no strings as well). This is a relatively easy shortcoming of the current implementation to fix, and user defined types for const generics will be possible in the nearer, rather than longer term.

I want to mention, since a lot of people aren’t aware of this, that not any type can be used as a const parameter, even setting aside the current limitations of rustc. Importantly, in order for Rust’s type system to be sound, equality between two types must be deterministic, reflexive, symmetric, and so on. That is, if your custom type implements equality by flipping a coin, two values of that type will sometimes be equal to one another and sometimes not. This will mean, two types parameterized by those values will sometimes be the same type and sometimes a different type. This would be quite troubling for the type system.

(As a concrete example, floating point numbers present challenges with the fact that Foo<NaN> , for example, would not be considered the same type as itself, because NaN is not equal to itself.)

The long term solution to this is a notion of “structural equality,” which is a strictly correct subset of Eq types that meet the properties needed for use in the type system. Rust already uses this structural equality property when implementing matching. If you derive Eq and PartialEq for your type and all its members, it should meet the structural equality property needed to be used in matches and const generics.

No complex expressions based on generic types or consts

The other limitation will be that only two kinds of expressions can be used to fill in a const generic position:

impl<const N: usize>

This limits a lot of the more exotic and interesting things users want to do with const generics. You can’t, for example, combine two array lengths together to form an array with type [T; {N + M}] , or even double an array length with [T; {N * 2}] . You basically can’t have a type that depends on computation that depends on other generics. Implementing this behavior soundly and correctly is really the hard part of implementing const generics, and while work is ongoing, it isn’t ready yet.

This also means that const generics can’t be filled in based on associated types, associated consts, or generic methods. No functions that return [u8; mem::size_of::<T>()] , no use of Self like [u8; Self::LEN] , etc.

This will mean, for example, that use cases like cryptographic hash traits which allow each implementation to specify a different length for the hash they output will still be out of scope for the MVP. This is a shame, but this feature will come eventually.

What you will be able to do

All of these restrictions might sound like the feature is pretty limited, but I think users will find a lot of really powerful use cases for it once they can play around with it. For one thing, traits that today might be implemented only by some array types, or not at all, will begin to be implemented by all arrays, making arrays a much more first class part of the language. And we’re already finding awesome use cases . Look at this code sample.

let data = [1, 2, 3, 4, 5, 6];

let sum1 = data.array_chunks().map(|&[x, y]| x * y).sum::<i32>();
assert_eq!(sum1, (1 * 2) + (3 * 4) + (5 * 6));

let sum2 = data.array_chunks().map(|&[x, y, z]| x * y * z).sum::<i32>();
assert_eq!(sum2, (1 * 2 * 3) + (4 * 5 * 6));

Based on the pattern passed to the map function, the compiler figures out that the first call to array_chunks should chunk the data into an iterator of arrays with length 2, and in the second call it should be an iterator of arrays with length 3. It’s so cool!

Next steps

Now that we’ve worked out what we could stabilize in the near future, I am working up hype and consensus aroud the vision of stabilizing this feature - that’s what this blog post is for! The next steps will be for someone to carve out a feature gate which is this limited set of const generics (as opposed to the existing whole const_generics feature gate) and then for us to go through the standard procedure for documenting and stabilizing that feature gate.

Credit

My own involvement in const generics between the RFC and now has been minimal to non-existent. Essentially, my role (both in the RFC and now) has been to identify a scope we can get consensus on moving forward with. However, the hard work of implementing const generics has been going on for years in between then, and I want to credit especially the contributors eddyb , varkor , lcnr , and oli-obk for their work on implementing this highly requested feature.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java夜未眠

Java夜未眠

蔡学镛 / 电子工业出版社 / 2003-4 / 20.00元

本书是一本散文集。作为一名资深程序设计师,作者走笔清新面独特,简练俏皮的文字下,是作者对工作,对人生的理性思考。书中收录的文章内容贴近程序员的生活,能令读者产生强烈共鸣。此外,书中的部分文章也以轻松的风格剖析了学习Java技术时的常见问题,并以专家眼光和经验推荐介绍了一批优秀的技术书籍,旨在帮助读者兴趣盎然地学习Java。一起来看看 《Java夜未眠》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具