Why can't you put constants in an impl block? - rust

Why does this code not work?
pub struct Foo {}
impl Foo {
const THREE: i32 = 3;
pub fn mul_three(num: i32) -> i32 {
num * THREE
}
pub fn sub_three(num: i32) -> i32 {
num - THREE
}
}
Compiler Explorer link
It works if the constant is moved up to the module level, or down into the functions. But although it is syntactically allowed where it is at currently, it's not usable:
error[E0425]: cannot find value `THREE` in this scope
--> <source>:6:15
|
6 | num * THREE
| ^^^^^ not found in this scope
What's the technical reason behind this?

You need to prefix it with Self:: (or Foo::), because it is part of the type:
pub struct Foo {}
impl Foo {
const THREE: i32 = 3;
pub fn mul_three(num: i32) -> i32 {
num * Self::THREE
}
pub fn sub_three(num: i32) -> i32 {
num - Self::THREE
}
}

Related

How to wrap a closure and still match a trait bound [duplicate]

I'm a newbie with Rust and I bumped into some obstacles when dealing with closures, either when returning them from functions and or methods, either when I need to store them as struct fields.
Let's start with what is working:
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo<F>
where
F: Fn(usize) -> usize,
{
fn new(foo: F) -> Self {
Self { foo }
}
}
fn main() {
let foo1 = Foo { foo: |a| a + 1 };
let foo2 = Foo { foo: build_func(2) };
let foo_func = build_func(3);
let foo3 = Foo { foo: foo_func };
}
This works as expected and the type of the closure that is built outside the struct is properly matched with the generic of Foo.
I wanted to achieve the same, but by hiding the creation of the closure simply by moving it inside the impl of Foo itself.
I tested these alternatives, but none of theme compiles:
struct Foo2<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
struct Foo3<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo3<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = |a| a + 1;
Self { foo }
}
}
struct Foo4<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo4<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> F {
move |a| a + b
}
}
struct Foo5<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo5<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
I understand that each closure has its own opaque and distinct type, but then I don't understand why on the other hand the initial implementation of Foo works then.
By reading the accepted answer here I seem to understand that the only option, in this case, would be to box the closure, but I still don't have a full understanding.
By combining boxed closure and trait aliases (I know it's not the "real" trait aliasing) I came up with this:
trait Func: Fn(usize) -> usize {}
impl<T> Func for T where T: Fn(usize) -> usize {}
struct Foo6 {
pub foo: Box<dyn Func>,
}
impl Foo6 {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Func {
move |a| a + b
}
}
fn main() {
let foo = Foo6::new();
println!("{}", (foo.foo)(1));
}
But I'm wondering whether it's possible to obtain an unboxed version.
The problem in this code:
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
is that to call it, the user code would need to write something like this:
let foo2 = <Foo2<?>>::new();
And specify some type there. Even if the type is not typed explicitly, it should be resolved there (type omission is mostly syntactic sugar). But the type of the stored value is decided inside that function, in the call to build_func(1), so the user has no type to use there and that function cannot be called.
My advice is to just write a free function:
fn new_foo2() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
Now the generic type is an impl in the return type of the function, that is an special opaque generic decided by the code of the function. So this works.
If you really, really want to write Foo2::new you can write the function implementation inside a dummy non-generic impl Foo2 block. Usually that would be impl Foo2<()> but the type () does not satisfies your constraints, but you can use any other dummy type that does:
impl Foo2<fn(usize)->usize> {
fn new() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
}
(Note that this new() does not return Self because the generic type is not correct.)
And now you can at least write:
let foo2 = Foo2::new();
The difference here is that you're returning Self from new(). Inside impl<F> Foo<F>, Self refers to Foo<F>. And F is a generic parameter - you cannot build a closure of type F, because it's a type your caller decides what it is, not you.
Your first version works because it tells the compiler "I will return some type implementing Fn; I'll leave it to you infer what exactly". On the other hand, the second versions are all "given any type F implementing Fn, I'll give you an instance of that type". That is of course impossible.
Instead you want the compiler to infer the used type here, too. The best solution will be to use impl Trait here, too. But impl Trait in positions other than return type is unstable. It will look like (playground):
#![feature(type_alias_impl_trait)]
type InnerFn = impl Fn(usize) -> usize;
struct Foo {
pub foo: InnerFn,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> InnerFn {
move |a| a + b
}
}
Another (quite hacky) solution is to have a generic parameter, but not use it and instead use impl Trait in new(). To not require the caller to specify the redundant parameter (since it can't be inferred anymore as it's unused), we can use a marker type, usually (). This requires us to remove the F: Fn(usize) -> usize bound from the struct and put it only on the impl, however this is a good style anyway (playground):
struct Foo<F> {
pub foo: F,
}
impl Foo<()> {
fn new() -> Foo<impl Fn(usize) -> usize> {
let foo = Self::build_func(1);
Foo { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
The last solution is indeed to box the closure, but you don't need a new trait for that - you can use Fn directly (playground):
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}

Design patterns without the box

Rust beginner here. I have a number of algorithms that are almost identical but, at the final step, they all aggregate the results in slightly differently ways. Let's say the Algorithm does the following:
pub struct Algorithm<T> {
result_aggregator: Box<dyn ResultAggregator<T>>,
}
impl<T> Algorithm<T> {
pub fn calculate(&self, num1: i32, num2: i32) -> T {
let temp = num1 + num2;
self.result_aggregator.create(temp)
}
}
With this, I can create a few different result aggregator classes to take my temp result and transform it into my final result:
pub trait ResultAggregator<T> {
fn create(&self, num: i32) -> T;
}
pub struct FloatAggregator;
pub struct StringAggregator;
impl ResultAggregator<f32> for FloatAggregator {
fn create(&self, num: i32) -> f32 {
num as f32 * 3.14159
}
}
impl ResultAggregator<String> for StringAggregator {
fn create(&self, num: i32) -> String {
format!("~~{num}~~")
}
}
...and call it like so:
fn main() {
// Here's a float example
let aggregator = FloatAggregator;
let algorithm = Algorithm {
result_aggregator: Box::new(aggregator),
};
let result = algorithm.calculate(4, 5);
println!("The result has value {result}");
// Here's a string example
let aggregator = StringAggregator;
let algorithm = Algorithm {
result_aggregator: Box::new(aggregator),
};
let result = algorithm.calculate(4, 5);
println!("The result has value {result}");
}
This is what I've come up with.
Question: Is it possible to do this without the dynamic box? It's performance critical and I understand that generics are usually a good solution but I've had no luck figuring out how to get it working without dynamic dispatch.
So what's the Rusty solution to this problem? I feel like I'm approaching it with my C# hat on which is probably not the way to go.
Link to the playground
You can use an associated type instead of a generic parameter:
pub trait ResultAggregator {
type Output;
fn create(&self, num: i32) -> Self::Output;
}
pub struct FloatAggregator;
pub struct StringAggregator;
impl ResultAggregator for FloatAggregator {
type Output = f32;
fn create(&self, num: i32) -> f32 {
num as f32 * 3.14159
}
}
impl ResultAggregator for StringAggregator {
type Output = String;
fn create(&self, num: i32) -> String {
format!("~~{num}~~")
}
}
pub struct Algorithm<Aggregator> {
result_aggregator: Aggregator,
}
impl<Aggregator: ResultAggregator> Algorithm<Aggregator> {
pub fn calculate(&self, num1: i32, num2: i32) -> Aggregator::Output {
let temp = num1 + num2;
self.result_aggregator.create(temp)
}
}

Extracting a function which creates an instance in Rust

A bit of a beginner Rust question - say I have the following code, which compiles:
trait XGetter {
fn get_x(&self) -> i32;
}
struct Foo {
x: i32
}
impl XGetter for Foo {
fn get_x(&self) -> i32 {
self.x
}
}
struct Bar<'a>(&'a dyn XGetter);
impl<'a> XGetter for Bar<'a> {
fn get_x(&self) -> i32 {
self.0.get_x()
}
}
fn baz() -> i32 {
let foo = Foo { x: 42 };
let bar = Bar(&foo);
bar.get_x()
}
Let's say I want to extract out the creation of Bar, in order encapsulate the creation of the XGetter and Bar together, such that baz() now reads:
fn baz2() -> i32 {
let bar = createBar(42);
bar.get_x()
}
However, by implementing createBar below, I run a-fowl of the borrow checker:
fn createBar<'a>(x: i32) -> Bar<'a> {
let foo = Foo { x };
let bar = Bar(&foo);
// ---- `foo` is borrowed here
bar
// ^^^ returns a value referencing data owned by the current function
}
How would one extract out a function createBar which doesn't break the borrowing rules?
The foo in createBar() dies when the function ends, so the bar you return would be pointing to invalid memory.
Given how you have written the call to createBar(42), it looks like you want Bar to own the Foo, so do that:
struct Bar(Box<dyn XGetter>);
impl XGetter for Bar {
fn get_x(&self) -> i32 {
self.0.get_x()
}
}
fn createBar(x: i32) -> Bar {
let foo = Box::new(Foo { x });
let bar = Bar(foo);
bar
}
You can not:
The signature struct Bar<'a>(&'a dyn XGetter); and createBar(i: 32) are incompatible. Because it means that in createBar you would have to instantiate an object implementing XGetter and that reference will not live outside of the scope of createBar.
fn createBar<'a>(x: i32) -> Bar<'a> {
let foo = Foo { x };
let bar = Bar(&foo);
// ---- `foo` is borrowed here
bar
// ^^^ returns a value referencing data owned by the current function
}
^^^ That means that the variable foo will live just during createBar scope.
That said, you could use:
fn createBar(g: &dyn XGetter) -> Bar<'_> {
Bar(g)
}
That way the reference will live outside of the scope of createBar.
Playground
As per the comments. If you want to abstract that, you need Bar to own Foo
struct Bar(Box<dyn XGetter>);
fn createBar(x: i32) -> Bar {
let foo = Box::new(Foo { x });
let bar = Bar(foo);
bar
}

How to implement bidirectional conversion with From trait in Rust?

Suppose I have the following type:
#[derive(Default)]
struct Foo(pub i32); // public
Since it's a tuple with a public member, any conversions from/to i32 can simply be made using the 0 member:
let foo = Foo::default();
let num: i32 = foo.0; // Foo to i32
let goo = Foo(123); // i32 to Foo
Now I want to make the 0 member non-public, implementing From trait:
#[derive(Default)]
struct Foo(i32); // non-public
impl From<i32> for Foo {
fn from(n: i32) -> Foo {
Foo(n)
}
}
But the conversion fails from i32 to Foo:
let foo = ay::Foo::default();
let num: i32 = foo.into(); // error!
let goo = ay::Foo::from(123); // okay
What's the correct way to implement this bidirectional conversion? Rust playground here.
You have to implement the other direction (impl From<Foo> for i32) manually:
mod x {
#[derive(Default)]
pub struct Foo(i32);
impl From<i32> for Foo {
fn from(n: i32) -> Foo {
Foo(n)
}
}
impl From<Foo> for i32 {
fn from(foo: Foo) -> i32 {
foo.0
}
}
}
fn main() {
let foo = x::Foo::default();
let _num: i32 = foo.into(); // okay
let _goo = x::Foo::from(123); // also okay
}
You can test this in the playground

How do I declare the implementation of a function that takes a trait that has a type parameter?

I have a trait with generic type. I want to define a struct with a property which meets that trait and I want to implement a function in that struct that uses the function inside the trait:
pub trait Point<I> {
fn id(&self) -> I;
}
pub struct Connection<T> {
pub to: T,
}
impl<T: Point> Connection<T> {
pub fn is_connected_to(&self, point: T) -> bool {
self.to.id() == point.id()
}
}
pub fn main() {
struct SimplePoint;
impl Point<char> for SimplePoint {
fn id(&self) -> char {
return 'A';
}
}
let a = SimplePoint {};
let conn = Connection { to: a };
}
(playground)
If I try to run this code, I get an error:
error[E0243]: wrong number of type arguments: expected 1, found 0
--> src/main.rs:9:9
|
9 | impl<T: Point> Connection<T> {
| ^^^^^ expected 1 type argument
If I try add a generic type:
impl<T: Point<I>> Connection<T> {
pub fn is_connected_to(&self, point: T) -> bool {
self.to.id() == point.id()
}
}
Then I get this error:
error[E0412]: cannot find type `I` in this scope
--> src/main.rs:9:15
|
9 | impl<T: Point<I>> Connection<T> {
| ^ did you mean `T`?
If I try to define the type I:
impl<I, T: Point<I>> Connection<T> {
pub fn is_connected_to(&self, point: T) -> bool {
self.to.id() == point.id()
}
}
The compiler tells me that I is unconstrained:
error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:9:6
|
9 | impl<I, T: Point<I>> Connection<T> {
| ^ unconstrained type parameter
How should I declare the implementation of the is_connected_to function?
A generic type must be monomorphized: each generic type must be resolved as a concrete type. If there is no constraint, the compiler cannot know what is the concrete type you want. You must put the generic type in the function:
pub trait Point<I: PartialEq> {
fn id(&self) -> I;
}
pub struct Connection<T> {
pub to: T
}
impl<T> Connection<T> {
pub fn is_connected_to<I: PartialEq>(&self, point: T) -> bool
where
T: Point<I>
{
self.to.id() == point.id()
}
}
pub fn main() {
struct SimplePoint;
impl Point<char> for SimplePoint{
fn id(&self) -> char { return 'A' }
}
let a = SimplePoint {};
let conn = Connection {
to: a
};
}

Resources