如何编写采用本身通用类型的泛型函数?

时间:2016-11-10 09:35:10

标签: generics rust

我希望编写一个函数,该函数采用不同类型的函数,这些函数主要在成员的(const / mut)中有所不同,它们本身采用泛型类型。

为了简化问题,我正在寻找一个带有常量或可变结构的函数。例如:

pub struct PtrConst<T> {
    ptr: *const T,
}
pub struct PtrMut<T> {
    ptr: *mut T,
}

我怎样才能编写一个带PtrConst<SomeType>PtrMut<SomeType>

的函数

这个片段相当长,但我试图简化它。

Playbook link.

// ---------------------------------------------------------------------------
// Test Case: This isn't working!

// How to make a generic function?
// See below for 'PtrConst' & 'PtrMut'.

pub trait PtrAnyFuncs {
    fn new() -> Self;
    fn is_null(&self) -> bool;
}

pub trait PtrAny:
    Deref +
    Copy +
    Clone +
    PartialEq +
    PtrAnyFuncs +
    {}

impl<TPtr> PtrAny for TPtr where TPtr:
    Deref +
    Copy +
    Clone +
    PartialEq +
    PtrAnyFuncs +
    {}


fn generic_test<T: PtrAny<MyStruct>>(a: T) {
    if a.is_null() {
        println!("Test: NULL");
    } else {
        println!("Test: {} {}", a.my_val_a, a.my_val_b);
    }
}


// ---------------------------------------------------------------------------
// Attempt to use generic function

struct MyStruct {
    pub my_val_a: usize,
    pub my_val_b: usize,
}

fn main() {
    let mut a: MyStruct = MyStruct { my_val_a: 10, my_val_b: 2, };
    let b: MyStruct = MyStruct { my_val_a: 4, my_val_b: 4, };

    let a_ptr = PtrMut::new(&mut a as *mut MyStruct);
    let b_ptr = PtrConst::new(&a as *const MyStruct);

    generic_test(a_ptr);
    generic_test(b_ptr);
}


// ---------------------------------------------------------------------------
// PtrMut

use std::ops::{
    Deref,
    DerefMut,
};

#[repr(C)]
#[derive(Hash)]
pub struct PtrMut<T> {
    ptr: *mut T,
}

impl<T> PtrAnyFuncs for PtrMut<T> {
    #[inline(always)]
    fn new(ptr: *mut T) -> PtrMut<T> {
        PtrMut { ptr: ptr as *mut T }
    }

    #[inline(always)]
    fn is_null(&self) -> bool {
        self.ptr == ::std::ptr::null_mut()
    }
}

impl<T> PtrMut<T> {
    #[inline(always)]
    pub fn null() -> PtrMut<T> {
        PtrMut { ptr: ::std::ptr::null_mut() }
    }

    #[inline(always)]
    pub fn as_pointer(&self) -> *mut T {
        self.ptr
    }

    // only for 'PtrMut'
    #[inline(always)]
    pub fn as_const(&self) -> PtrConst<T> {
        PtrConst::new(self.ptr as *const T)
    }
}

impl<T> Copy for PtrMut<T> { }
impl<T> Clone for PtrMut<T> {
    #[inline(always)]
    fn clone(&self) -> PtrMut<T> { *self }
}

impl<T> Deref for PtrMut<T> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for PtrMut<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T> PartialEq for PtrMut<T> {
    fn eq(&self, other: &PtrMut<T>) -> bool {
        self.ptr == other.ptr
    }
}

// ---------------------------------------------------------------------------
// PtrConst

#[repr(C)]
#[derive(Hash)]
pub struct PtrConst<T> {
    ptr: *const T,
}

impl<T> PtrAnyFuncs for PtrConst<T> {
    #[inline(always)]
    fn new(ptr: *const T) -> PtrConst<T> {
        PtrConst { ptr: ptr as *const T }
    }

    #[inline(always)]
    fn is_null(&self) -> bool {
        self.ptr == ::std::ptr::null_mut()
    }
}

impl<T> PtrConst<T> {

    #[inline(always)]
    pub fn null() -> PtrConst<T> {
        PtrConst { ptr: ::std::ptr::null_mut() }
    }

    #[inline(always)]
    pub fn as_pointer(&self) -> *const T {
        self.ptr
    }
}

impl<T> Copy for PtrConst<T> { }
impl<T> Clone for PtrConst<T> {
    #[inline(always)]
    fn clone(&self) -> PtrConst<T> { *self }
}

impl<T> Deref for PtrConst<T> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

// no DerefMut for PtrConst, only PtrMut
impl<T> PartialEq for PtrConst<T> {
    fn eq(&self, other: &PtrConst<T>) -> bool {
        self.ptr == other.ptr
    }
}

2 个答案:

答案 0 :(得分:2)

解决方案是使你的特质在指针类型上具有通用性:

pub trait PtrAny<T>: ...

impl<T, TPtr> PtrAny<T> for TPtr where TPtr: ...

请注意,这并不能解决您的链接代码示例,因为Rust无法提取(非)可变性。

答案 1 :(得分:0)

感谢@futile&amp; IRC上的@oli_obk_,这是问题中代码的一个工作示例。

  • PtrAnyPtrAnyFuncs需要提供类型。
  • PtrAnyFuncs需要使用相关类型,因此new的参数可以在*mut*const之间变为通用。
  • Deref需要声明它取消引用Deref<Target=T>
  • 的类型

工作代码:

pub trait PtrAnyFuncs<T> {
    type InnerPtr;

    fn new(ptr: Self::InnerPtr) -> Self;
    fn is_null(&self) -> bool;
}

pub trait PtrAny<T>:
    Deref<Target=T> +
    Copy +
    Clone +
    PartialEq +
    PtrAnyFuncs<T> +
    {}

impl<TPtr, T> PtrAny<T> for TPtr where TPtr:
    Deref<Target=T> +
    Copy +
    Clone +
    PartialEq +
    PtrAnyFuncs<T> +
    {}

fn generic_test<T: PtrAny<MyStruct>>(a: T) {
    if a.is_null() {
        println!("Test: NULL");
    } else {
        println!("Test: {} {}", a.my_val_a, a.my_val_b);
    }
}


// ---------------------------------------------------------------------------
// Attempt to use generic function

struct MyStruct {
    pub my_val_a: usize,
    pub my_val_b: usize,
}

fn main() {
    let mut a: MyStruct = MyStruct { my_val_a: 10, my_val_b: 2, };
    let b: MyStruct = MyStruct { my_val_a: 4, my_val_b: 4, };

    let a_ptr = PtrMut::new(&mut a as *mut MyStruct);
    let b_ptr = PtrConst::new(&b as *const MyStruct);

    generic_test(a_ptr);
    generic_test(b_ptr);
}


// ---------------------------------------------------------------------------
// PtrMut

use std::ops::{
    Deref,
    DerefMut,
};

#[repr(C)]
#[derive(Hash)]
pub struct PtrMut<T> {
    ptr: *mut T,
}

impl<T> PtrAnyFuncs<T> for PtrMut<T> {
    type InnerPtr = *const T;

    #[inline(always)]
    fn new(ptr: Self::InnerPtr) -> PtrMut<T> {
        PtrMut { ptr: ptr as *mut T }
    }

    #[inline(always)]
    fn is_null(&self) -> bool {
        self.ptr == ::std::ptr::null_mut()
    }
}

impl<T> PtrMut<T> {

    #[inline(always)]
    pub fn null() -> PtrMut<T> {
        PtrMut { ptr: ::std::ptr::null_mut() }
    }

    #[inline(always)]
    pub fn as_pointer(&self) -> *mut T {
        self.ptr
    }

    // only for 'PtrMut'
    #[inline(always)]
    pub fn as_const(&self) -> PtrConst<T> {
        PtrConst::new(self.ptr as *const T)
    }
}

impl<T> Copy for PtrMut<T> { }
impl<T> Clone for PtrMut<T> {
    #[inline(always)]
    fn clone(&self) -> PtrMut<T> { *self }
}

impl<T> Deref for PtrMut<T> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for PtrMut<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T> PartialEq for PtrMut<T> {
    fn eq(&self, other: &PtrMut<T>) -> bool {
        self.ptr == other.ptr
    }
}

// ---------------------------------------------------------------------------
// PtrConst

#[repr(C)]
#[derive(Hash)]
pub struct PtrConst<T> {
    ptr: *const T,
}

impl<T> PtrAnyFuncs<T> for PtrConst<T> {
    type InnerPtr = *const T;

    #[inline(always)]
    fn new(ptr: Self::InnerPtr) -> PtrConst<T> {
        PtrConst { ptr: ptr as *const T }
    }

    #[inline(always)]
    fn is_null(&self) -> bool {
        self.ptr == ::std::ptr::null_mut()
    }
}

impl<T> PtrConst<T> {
    #[inline(always)]
    pub fn null() -> PtrConst<T> {
        PtrConst { ptr: ::std::ptr::null_mut() }
    }

    #[inline(always)]
    pub fn as_pointer(&self) -> *const T {
        self.ptr
    }
}

impl<T> Copy for PtrConst<T> { }
impl<T> Clone for PtrConst<T> {
    #[inline(always)]
    fn clone(&self) -> PtrConst<T> { *self }
}

impl<T> Deref for PtrConst<T> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

// no DerefMut for PtrConst, only PtrMut
impl<T> PartialEq for PtrConst<T> {
    fn eq(&self, other: &PtrConst<T>) -> bool {
        self.ptr == other.ptr
    }
}