How to call associated function with array or tuple type?
Asked Answered
I

2

5

I can define an associated function foo for an array like this:

pub trait T {
    fn foo();
}

impl<X> T for [X; 2] {
    fn foo() { panic!("Whatever") }
}

But how do I now call this function? I noticed that syntax like [usize;2]::foo() is invalid.

Ichthyosis answered 10/4, 2022 at 16:47 Comment(0)
U
4

Short answer: You need to use angle brackets: <[usize; 2]>::foo().

Long answer:

If you'll look in the reference, you'll see the syntax:

CallExpression :
      Expression ( CallParams? )

Inside Expression, you have PathExpression. There are two kinds of PathExpression s: PathInExpression and QualifiedPathInExpression. PathInExpression is a simple path of the form a::b::c::<generics>::d::<generics> etc.. This is what you use when you type e.g. String::new() or String::from("abc").

QualifiedPathInExpression, on the other hand, has the form QualifiedPathType (:: PathExprSegment)+, or in simple words, QualifiedPathType followed by one or more instances of two colons then PathExprSegement. PathExprSegment is defined as a name (identifier) optionally followed by two colons and generics: i.e., foo or foo::<a, b, c>.

And what is QualifiedPathType ? It is defined as < Type (as TypePath)? >, or a type enclosed in angle brackets, optionally followed by as and a TypePath, which is very similar to PathExpression with some differences.

Type is any Rust type syntax: a path (e.g. a::b<generics> or a::b::<generics>, trait objects (dyn Trait), impl Trait, tuples ((T1, T2, T3, ...)), arrays ([T; N]), slices ([T]), references (&T or &mut T, potentially with a lifetime), and more.

All of this means that when you call a method, unless the method type is a simple path - that is, has the form a::b::c, potentially with generics, you must enclose the type in angle brackets - <Type>::method(). That includes arrays, slices, references, tuples, function pointers (fn(Args) -> Ret), and more. [usize; 2]::foo() is not a valid Rust syntax, only <[usize; 2]>::foo() is.

Of course, there is another reason to use this form: UFCS (Universal Function Call Syntax). When you want to specify the trait (usually for disambiguition), you must use the form <Type as Trait>::method() (this is the "(as TypePath)?" we saw).

Urinalysis answered 11/4, 2022 at 2:15 Comment(0)
G
7

You can use the fully qualifidied syntax <Type as Trait>::function(). Here is your example:

pub trait Trait {
    fn foo();
}

impl<X> Trait for [X; 2] {
    fn foo() {
        panic!("Whatever");
    }
}

fn main() {
    <[usize; 2] as Trait>::foo();
}

See it on the playground.

Gadwall answered 10/4, 2022 at 16:53 Comment(0)
U
4

Short answer: You need to use angle brackets: <[usize; 2]>::foo().

Long answer:

If you'll look in the reference, you'll see the syntax:

CallExpression :
      Expression ( CallParams? )

Inside Expression, you have PathExpression. There are two kinds of PathExpression s: PathInExpression and QualifiedPathInExpression. PathInExpression is a simple path of the form a::b::c::<generics>::d::<generics> etc.. This is what you use when you type e.g. String::new() or String::from("abc").

QualifiedPathInExpression, on the other hand, has the form QualifiedPathType (:: PathExprSegment)+, or in simple words, QualifiedPathType followed by one or more instances of two colons then PathExprSegement. PathExprSegment is defined as a name (identifier) optionally followed by two colons and generics: i.e., foo or foo::<a, b, c>.

And what is QualifiedPathType ? It is defined as < Type (as TypePath)? >, or a type enclosed in angle brackets, optionally followed by as and a TypePath, which is very similar to PathExpression with some differences.

Type is any Rust type syntax: a path (e.g. a::b<generics> or a::b::<generics>, trait objects (dyn Trait), impl Trait, tuples ((T1, T2, T3, ...)), arrays ([T; N]), slices ([T]), references (&T or &mut T, potentially with a lifetime), and more.

All of this means that when you call a method, unless the method type is a simple path - that is, has the form a::b::c, potentially with generics, you must enclose the type in angle brackets - <Type>::method(). That includes arrays, slices, references, tuples, function pointers (fn(Args) -> Ret), and more. [usize; 2]::foo() is not a valid Rust syntax, only <[usize; 2]>::foo() is.

Of course, there is another reason to use this form: UFCS (Universal Function Call Syntax). When you want to specify the trait (usually for disambiguition), you must use the form <Type as Trait>::method() (this is the "(as TypePath)?" we saw).

Urinalysis answered 11/4, 2022 at 2:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.