lang (syntax | const)
const_wildcard
Allow assigning constants to _
, as in const _: TYPE = VALUE
, analogous to
let _ = VALUE
.
The ability to ensure that code type checks while discarding the result is
useful, especially in custom derives. For example, the following code will not
compile if the type MyType
doesn't implement the trait MyTrait
:
const _FOO: () = {
use std::marker::PhantomData;
struct ImpelementsMyTrait<T: MyTrait>(PhantomData<T>);
let _ = ImplementsMyTrait::<MyType>(PhantomData); // type checking error if MyType: !MyTrait
()
};
Unfortunately, this requires coming up with a unique identifier to assign to.
This is error-prone because no matter what identifier is chosen, there's always
a possibility that a user will have already used the same identifier in their
code. If writing const _: () = { ... }
were valid, then this would be a
non-issue - the const _
could be repeated many times without conflicting with
any other identifier in scope.
Allow assigning to _
when defining a new constant. Just like let _
, this
doesn't introduce any new bindings, but still evaluates the rvalue at compile
time like any other constant.
The following changes are made to the language:
The grammar of item_const
is changed from:
item_const : CONST ident ':' ty '=' expr ';' ;
to:
item_const : CONST (ident | UNDERSCORE) ':' ty '=' expr ';' ;
When type checking an associated const
item, the token _
may not occur as
the name of the item.
When type checking a const
item not inside an impl
item, the token _
is
permitted as the name of such an item. When that token does occur, it is
replaced with a freshly generated and unique identifier.
The rules around constant identifiers are made somewhat more complicated, as is
the compiler logic for handling them. A distinction is introduced between
associated const
items (inside impl
s) and non-associated const
items.
This would allow more ergonomic uses of a number of patterns used today:
const_assert!
and other macros in the
static_assertions
crate, which currently work only in a scope (so that they can use a let
binding) or requires the user to specify a scope-unique name for a function
which will be used to contain the expression that is the meat of the macro.Eventually, we will likely want to support fully general pattern matching just
like in let
bindings (e.g., const (a, b): (u8, u8) = (1, 1)
) to not have
const _
be a special case in the language. However, this RFC leaves the
details of such a design up to a future RFC.
mod { ... }
or mod _ { ... }
).fn _() { ... }
).Go allows unnamed constants using the syntax const _ = ...
. It also allows
top-level variable bindings which are evaluated at init time, before main
is
run - var _ = ...
. This latter syntax is often used to ensure that a
particular type implements a particular interface, as in this example from the
standard library:
var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
None.