Matthieu M.
Matthieu M.

Reputation: 300079

How do I alias the type of self in a struct method?

If I have a small struct Test:

struct Test<T> { a: T }

And I wish, in a method of Test to refer to its full type:

impl<T> Test<T> {
    fn new(a: T) -> Test<T> {
        type X = Test::<T>;
        println!("{}", std::intrinsics::type_id::<X>());
        Test { a: a }
    }
}

This fails with expected ident, found <, and the following fail too:

Actually, it makes sense that the former two are rejected; the latter however is slightly more mysterious.

This came about in trying to implement an offset_of! macro: offset_of($T:ty, $field:ident); the macro works rather well, however ty does not accept Test<T> (but accept a parameter-less alias).

Is there any way to either:

Note: I would prefer a solution to the former, if possible, as aliases are really handy.


For reference, here is the offset_of macro I crafted:

macro_rules! offset_of(
    ($T:ty, $field:ident) => {
        unsafe {
            let exemplar: $T = std::mem::uninitialized();
            let base: *const u8 = std::mem::transmute(&exemplar);
            let attr: *const u8 = std::mem::transmute(&exemplar.$field);
            std::mem::forget(exemplar);
            (attr as isize) - (base as isize)
        }
    }
);

Upvotes: 2

Views: 1301

Answers (1)

Shepmaster
Shepmaster

Reputation: 431589

I may be misunderstanding you, but there already is an alias for the type of self — Self:

#![feature(core)]

struct Test<T> { a: T }

impl<T> Test<T> {
    fn new(a: T) -> Test<T>
        where T: 'static
    {
        println!("{}", unsafe { std::intrinsics::type_id::<Self>() });
        Test { a: a }
    }
}

fn main() {}

I had to add the feature gates, make T 'static to satisfy type_id, and add an unsafe block. I hope that none of that seems suspicious. This seems to work with your alias, as well:

macro_rules! offset_of(
    ($T:ty, $field:ident) => {
        unsafe {
            let exemplar: $T = std::mem::uninitialized();
            let base: *const u8 = std::mem::transmute(&exemplar);
            let attr: *const u8 = std::mem::transmute(&exemplar.$field);
            (attr as isize) - (base as isize)
        }
    }
);

struct Test<T> { a: T, b: T, c: T }

impl<T> Test<T> {
    fn new(a: T) -> Test<T>
        where T: Copy
    {
        println!("{}", offset_of!(Self, a));
        println!("{}", offset_of!(Self, b));
        println!("{}", offset_of!(Self, c));
        Test { a: a, b: a, c: a }
    }
}

fn main() {
    Test::new(1u16);
}

Upvotes: 3

Related Questions