Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a foreign trait for a local generic type

Tags:

rust

I'm attempting to implement a trait from crate A for a trait from crate B using static dispatch. I'm wrapping the foreign trait, but am having trouble with the impl<T> line:

extern crate a;
extern crate b;

pub trait C: a::A {}

impl<T: C> b::B for T {}

The end result I am looking for is implementing b::B for implementors of trait C, using static dispatch.

I'm getting the following error:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
 --> c/src/lib.rs:3:1
  |
3 | impl<T: C> b::B for T {}
  | ^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
  |
  = note: only traits defined in the current crate can be implemented for a type parameter

I'm able to get around this by using dynamic dispatch — impl b::B for dyn C — but want to accomplish this with static dispatch.

I've already tried:

  • Error E0201 when implementing foreign trait for local type with parameter — I'm not trying to implement a trait for Vec, but my own type
  • I implemented a trait for another trait but cannot call methods from both traits — The types don't conflict
  • The trait cannot be made into an object — I want to use static dispatch
like image 568
Kellen Avatar asked Oct 16 '19 15:10

Kellen


People also ask

What are the advantages of generics over trait objects?

Generics have two major advantages over trait objects: Speed. When the compiler generates machine code for a generic function, it knows which types it's working with, so it knows at that time which writemethod to call. No need for dynamic dispatch.

What is a generic function?

Intro to Generics A generic function or type can be used with values of many different types.

What is a trait in programming?

A trait is a feature that any given type may or may not support. Think of a trait as a type capability. Rule: For trait methods to be accessible, the trait itself must be in scope! Otherwise, all of its methods are hidden. #![allow(unused)] fn main() { let mut buf: Vec<u8> = vec![]; buf.write_all(b"hello!")?; // ERR: no method named write_all }

What is the difference between generic implblocks and term?

Term: A trait that adds a single method to a type is called an extension traits. Generic implblocks can be used to add an extension trait to a whole family of types at once.


1 Answers

What I usually do is wrapping the foreign type in a struct (as opposed to introducing a new trait deriving from the foreign one):

extern crate a;
extern crate b;

pub struct C<T: a::A> {
    pub t: T,
}

impl<T: a::A> b::B for C<T> {}

This, however, sometimes requires some boilerplate to convert between C and the "normal" type.

This is sometimes called "NewType pattern" (as in https://github.com/Ixrec/rust-orphan-rules).

like image 134
phimuemue Avatar answered Sep 29 '22 07:09

phimuemue