簡體   English   中英

在 Rust nightly 中使用關聯的常量和常量泛型時的類型不匹配

[英]Mismatched types when using associated consts and const generics in Rust nightly

因此,對於我正在編寫的庫,我想計算 N 維(2、3、4 等...)中兩點之間的距離,並且我有一個 Point 特征,以便庫的用戶可以在他們的自己的類型,只要它們是“點像”。

我有一個特征“Point”,它的維度 (N) 和浮點類型 (T) 保持為關聯類型和常量:

pub trait Point: Copy + Clone {
    type T: num::Float;
    const N: usize;

    fn as_array(&self) -> [Self::T; Self::N];
}

以及使用它的函數:

fn dist<P>(a: &P, b: &P) -> P::T
where
    P: Point,
    [(); P::N]: ,
{
    // implementation goes here ...
}

按預期使用 Point 特征的示例:

#[derive(Copy, Clone)]
struct MyCustomPoint { a: f64, b: f64 }

impl Point for MyCustomPoint {
    type T = f64;
    const N: usize = 2;

    fn as_array(&self) -> [Self::T; Self::N] {
        [self.a, self.b]
    }
}

問題

如果我為 [f32;N] 實現 Point trait,我會遇到以下問題:

error[E0308]: mismatched types
  --> src\main.rs:63:9
   |
63 |         *self
   |         ^^^^^ expected `Self::N`, found `N`
   |
   = note: expected type `Self::N`
              found type `N`

導致問題的代碼:

impl<const N: usize> Point for [f32; N] {
    type T = f32;
    const N: usize = N;

    fn as_array(&self) -> [Self::T; Self::N] {
        *self
    }
}

當在代碼中使用數字時,為什么下面的代碼會導致類型不匹配錯誤?

impl Point for [f32; 3] {
    type T = f32;
    const N: usize = 3;

    fn as_array(&self) -> [Self::T; Self::N] {
        *self
    }
}

所有代碼放在一個塊中:

#![feature(adt_const_params)]
#![feature(generic_const_exprs)]

use num::Float;

pub trait Point: Copy + Clone {
    type T: num::Float;
    const N: usize;

    fn as_array(&self) -> [Self::T; Self::N];
}

fn dist<P>(a: &P, b: &P) -> P::T
where
    P: Point,
    [(); P::N]: ,
{
    let mut dist_sq: P::T = num::zero();
    for i in 0..P::N {
        let delta = (a.as_array())[i] - (b.as_array())[i];
        dist_sq = dist_sq + delta * delta;
    }
    dist_sq.sqrt()
}

// Works
#[derive(Copy, Clone)]
struct MyCustomPoint { a: f64, b: f64 }

impl Point for MyCustomPoint {
    type T = f64;
    const N: usize = 2;

    fn as_array(&self) -> [Self::T; Self::N] {
        [self.a, self.b]
    }
}

// Works
// impl Point for [f32; 3] {
//     type T = f32;
//     const N: usize = 3;

//     fn as_array(&self) -> [Self::T; Self::N] {
//         *self
//     }
// }

// Doesn't work
impl<const N: usize> Point for [f32; N] {
    type T = f32;
    const N: usize = N;

    fn as_array(&self) -> [Self::T; Self::N] {
        *self
    }
}

fn main() {
    let a = [0f32, 1f32, 0f32];
    let b = [3f32, 1f32, 4f32];
    assert_eq!(dist(&a, &b), 5f32);
}

另外,我發現以下是一種解決方法。

fn as_array(&self) -> [Self::T; Self::N] {
    // *self

    // Workaround - replace with something simpler if possible.
    let mut array = [0f64; Self::N];
    array[..Self::N].copy_from_slice(&self[..Self::N]);
    array
}

只使用穩定的 Rust,我相信你可以實現你想要的。 假設您想要的效果只是能夠在任意(但相同)維度的數組上調用dist()或具有相同通用參數值並從.as_array()返回相同大小數組的 Point 對象.

.as_array()方法添加到所有浮點值數組,遵循一個共同的模式,即聲明一個特征以追溯地向現有類型添加特征。

use num::Float;

pub trait Point<T: Float, const N: usize>: Copy + Clone {
    fn as_array(&self) -> [T; N];
}

impl<T: Float, const N: usize> Point<T, N> for [T; N] {
    fn as_array(&self) -> [T; N] {
        *self
    }
}

然后是一個函數,它采用正確的泛型組合供編譯器根據其參數進行定制。

fn dist<P, T, const N: usize>(a: &P, b: &P) -> T
where
    P: Point<T, N>,
    T: Float,
{
    let mut dist_sq: T = num::zero();
    for i in 0..N {
        let delta = (a.as_array())[i] - (b.as_array())[i];
        dist_sq = dist_sq + delta * delta;
    }
    dist_sq.sqrt()
}

這使代碼如下:

fn main() {
    let a = [0f32, 1f32, 0f32];
    let b = [3f32, 1f32, 4f32];
    assert_eq!(dist(&a, &b), 5f32);
    println!("dist(&a, &b): {}", dist(&a, &b));
    
    let c = [1f64, 2f64, 3f64, 4f64,  5f64];
    let d = [6f64, 7f64, 8f64, 9f64, 10f64];
    
    println!("dist(&c, &d): {}", dist(&c, &d));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM