error[E0401]: can't use generic parameters from outer function
--> src/main.rs:17:19
|
16 | fn read<T>(cursor: &mut dyn Read) -> Result<T, Error> {
| - type parameter from outer function
17 | const BYTES = T::BITS/8;
| ^^^^^^^ use of generic parameter from outer function
Shouldn't that be allowed, now that we can have numeric parameters to generics? Is there a workaround? Is there a way to get the size of a type as a const?
The way to think about items such as const, trait, type, or fn is that while they are allowed to appear inside of a function body, they still have to be defined in such a way that they could equally well be pulled outside of that function body. That’s why T isn’t allowed in the const. Similarly:
doesn’t work. The way to do compile-time but type-dependent stuff is by const fn, or with traits with associated items. By the way, I don’t know where the associated item BITS is supposed to come from, maybe you’re missing a trait or something in your code example?
Edit:
The way to do compile-time but type-dependent stuff is by const fn, or with traits with associated items.
actually, that might be wrong; maybe what you want isn’t possible on stable yet. I tried some stuff with a trait with an associated const BITS and I keep getting error: generic parameters may not be used in const operations.
An item is a thing that can be put at top-level in Rust, a let … = …; statement is not an item. On the other hand, while items can technically count as statements, they’re really in essence not really part of the function or block they live in except for visibility concerns; so it’s best to think of items and statements of really different things. This means that a const …: … = …; is something entirely different from a let-statement in lots of ways, it isn’t just “a let-statement with some ‘const-ness’ constraints” or anything like that.
More on items as statements can be read in the reference here which is a section of the “Statements” page linked above. In particular, try to understand this part and relate it to the examples I gave above:
[…] It is otherwise identical in meaning to declaring the item inside a module.
There is no implicit capture of the containing function's generic parameters, parameters, and local variables. For example, inner may not access outer_var .
fn outer() {
let outer_var = true;
fn inner() { /* outer_var is not in scope here */ }
inner();
}
That applies to a local variable, reasonably enough, because otherwise you could create a closure that way. It doesn't apply to an "item".
// Nesting test
pub fn outer() {
struct St {
pub x: f32
}
const X: f32 = 1.0;
fn fn1()-> St {
let st = St{x: X};
st
}
let stout = fn1();
println!("{}", stout.x)
}
X and St, being compile-type objects, are visible within fn1.
So this isn't a general scope issue, it's a special problem with generics. One that really should have been fixed when const parameters came in, since the whole point of that was to improve behavior around items whose size is determined at compile time.