44

This program dies because of infinite recursion:

use std::any::Any;

trait Foo {
    fn get(&self, index: usize) -> Option<&Any>;
}

impl Foo for Vec<i32> {
    fn get(&self, index: usize) -> Option<&Any> {
        Vec::get(self, index).map(|v| v as &Any)
    }
}

fn main() {
    let v: Vec<i32> = vec![1, 2, 4];
    println!("Results: {:?}", v.get(0))
}

The compiler itself warns about this:

warning: function cannot return without recurring
  --> src/main.rs:8:5
   |
8  |       fn get(&self, index: usize) -> Option<&Any> {
   |  _____^ starting here...
9  | |         Vec::get(self, index).map(|v| v as &Any)
10 | |     }
   | |_____^ ...ending here
   |
   = note: #[warn(unconditional_recursion)] on by default
note: recursive call site
  --> src/main.rs:9:9
   |
9  |         Vec::get(self, index).map(|v| v as &Any)
   |         ^^^^^^^^^^^^^^^^^^^^^
   = help: a `loop` may express intention better if this is on purpose

Why does universal call syntax not work in this case? The compiler does not understand that I want to call Vec::get not Foo::get.

How can I fix this, if I do not want to change function names?

1 Answer 1

52

To specify which method to call, whether inherent or provided from a trait, you want to use the fully qualified syntax:

Type::function(maybe_self, needed_arguments, more_arguments)
Trait::function(maybe_self, needed_arguments, more_arguments)

Your case doesn't work because Vec doesn't have a method called get! get is provided from the Deref implementation to [T].

The easiest fix is to call as_slice directly:

self.as_slice().get(index).map(|v| v as &Any)

You could also use the fully qualified syntax which requires the angle brackets in this case (<...>) to avoid ambiguity with declaring an array literal:

<[i32]>::get(self, index).map(|v| v as &Any)

universal call syntax

Note that while Rust originally used the term universal function call syntax (UFCS), the usage of this term conflicted with the existing understood programming term, so the use of it is not suggested. The replacement term is fully qualified syntax.

Sign up to request clarification or add additional context in comments.

3 Comments

If it is Deref, should <Vec<i32> as Deref>::get(self, index) also do the trick?
@user1244932 an interesting question, but it doesn't appear so. The whole point of this syntax is to be unambiguous, so <T as Deref> would mean "only the methods on the Deref trait", but get isn't such a method.
Note that when using the <T>::foo syntax to pay attention to whether the impl providing foo is on T or &T or &mut T. I spent a bunch of time trying to figure out why inside by impl on &mut [u8] I couldn't call the builtin slice len method with <&mut [u8]>::len which was just picking up my own len method. I needed <[u8]>::len.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.