1

I have function that is part of a struct (for context reasons) which does not take the self parameter. Furthermore, the struct itself takes a generic parameter T with some trait restrictions:

trait SomeRestriction {}
struct SomeStruct<T: SomeRestriction>(T);

impl<T: SomeRestriction> SomeStruct<T> {
    fn some_function_that_does_not_take_self() -> String {
        todo!()
    }
}

I want to write a test and I would like to avoid giving that function the self parameter since mocking the object with some generic struct parameter is a lot of effort for that small function and test.

I do it for the other tests since it is necessary there, but I would like to avoid it wherever I can.

I tried to call it like this:

let some_string = SomeStruct::some_function_that_does_not_take_self();

but it will ask me for a type annotation even though it is not needed.

Is there a way to call it without mocking the struct or removing the function from the struct implementation?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Melvin
  • 407
  • 5
  • 16

2 Answers2

4

Is there a way to call it without mocking the struct or removing the function from the struct implementation?

No. For all Rust knows SomeStruct<T>::some_function_that_does_not_take_self is completely distinct for each T. They could have different behavior, too, consider this:

use core::fmt::Debug;

#[derive(Debug, Default)] struct A;
#[derive(Debug, Default)] struct B;

struct C<T> { t: T }
impl<T: Debug + Default> C<T> {
    fn foo() { println!("{:?}", T::default()) }
}

fn main() {
    C::<A>::foo(); // Prints 'A'.
    C::<B>::foo(); // Prints 'B'.
}
orlp
  • 112,504
  • 36
  • 218
  • 315
  • 1
    Alright, thanks! So for tests I will just use one of the types intended for the struct and call it like that: ```let some_string = SomeStruct::::some_function()``` – Melvin Jul 02 '21 at 17:40
0

As orlp said: no, you must provide a concrete type.

is a lot of effort for that small function and test

For your specific example, you can write the code differently so that the concrete type is easier to provide by removing the trait bounds where it isn't needed:

trait SomeRestriction {}
struct SomeStruct<T>(T);

impl<T> SomeStruct<T> {
    fn some_function_that_does_not_take_self() -> String { todo!() }
}

impl<T: SomeRestriction> SomeStruct<T> {
    // functions that actually use `T`
}

fn main() {
    let some_string = SomeStruct::<()>::some_function_that_does_not_take_self();
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    You could of course also provide a default type in the struct definition: `struct SomeStruct(T);`—then there would no longer be any need to provide an explicit type in the associated function call if the default type is acceptable. – eggyal Jul 02 '21 at 21:26
  • 1
    Or, if for some reason adding a default type is not acceptable, one could have a type alias `type UnitSomeStruct = SomeStruct<()>;` and call the associated function through that. – eggyal Jul 02 '21 at 21:42