【问题标题】:expected fn pointer, found fn item预期的 fn 指针,找到 fn 项
【发布时间】:2022-07-19 22:03:09
【问题描述】:

我想使用函数指针来指向下面这两个函数中的任何一个。 直接调用时,这两个函数都按预期工作。

当我想使用指针时,它们的类型不兼容,即使它们具有相同的参数a: &'a [T], b: &'a [T] 并且都返回f64

use ndarray::linalg::Dot;
use ndarray::{ArrayView, ArrayBase, RawData};

#[inline]
pub fn euclidean_distance<'a, T>(a: &'a [T], b: &'a [T]) -> f64
where
    f64: From<T>,
    T: Copy,
{
    a.iter()
        .zip(b.iter())
        .fold(0f64, |acc, (&x, &y)| {
            acc + (f64::from(x) - f64::from(y)).powi(2)
        })
        .sqrt()
}

#[inline]
pub fn cosine<'a, T>(a: &'a [T], b: &'a [T]) -> f64
where
    T: Copy,
    ArrayView<'a, T, Ix1>: Dot<ArrayView<'a, T, Ix1>, Output = f64>,
{
    let x = ArrayView::from(a);
    let y = ArrayView::from(b);
    x.dot(&y) / (x.dot(&x) * y.dot(&y)).sqrt()
}

什么时候,我想使用指向这些函数的指针

pub struct Model<'a, T>
where
    T: Copy,
    f64: From<T>,
{
    /// Epsilon value - maximum distance between points in a cluster
    pub eps: f64,
    /// Minimum number of points in a cluster
    pub mpt: usize,

    distance: fn(a: &'a [T], b: &'a [T]) -> f64,
    c: Vec<Classification>,
    v: Vec<bool>,
}

impl<'a, T> Model<'a, T>
where
    T: Copy,
    f64: From<T>,
{
    /// Create a new `Model` with a set of parameters
    ///
    /// # Arguments
    /// * `eps` - maximum distance between datapoints within a cluster
    /// * `min_points` - minimum number of datapoints to make a cluster
    pub fn new(eps: f64, min_points: usize, mode: &str) -> Model<T> {
        Model {
            eps,
            mpt: min_points,
            c: Vec::new(),
            v: Vec::new(),
            distance: match mode {
                "euclidean" => euclidean_distance,
                "cosine" => cosine,
                _ => panic!("Unknown Mode {:?}", mode),
            },
        }
    }
}

我收到以下错误:“预期 fn 指针,找到 fn 项”。我不明白为什么这些函数有不同的不兼容类型。

error[E0308]: `match` arms have incompatible types
   --> src/dbscan.rs:115:29
    |
113 |               distance: match mode {
    |  _______________________-
114 | |                 "euclidean" => euclidean_distance,
    | |                                ------------------ this is found to be of type `fn(&[T], &[T]) -> f64`
115 | |                 "cosine" => cosine,
    | |                             ^^^^^^ expected fn pointer, found fn item
116 | |                 _ => panic!("Unknown Mode {:?}", mode),
117 | |             },
    | |_____________- `match` arms have incompatible types
    |
    = note: expected fn pointer `fn(&[T], &[T]) -> _`
                  found fn item `fn(&[f64], &[f64]) -> _ {dbscan::cosine::<'_, f64>}`

【问题讨论】:

标签: rust


【解决方案1】:

它只需要一些小的生命周期调整,impl Model 中缺少一个 where 子句:

use ndarray::linalg::Dot;
use ndarray::{ArrayView, Ix1};

struct Classification;

#[inline]
pub fn euclidean_distance<T>(a: &[T], b: &[T]) -> f64
where
    f64: From<T>,
    T: Copy,
{
    a.iter()
        .zip(b.iter())
        .fold(0f64, |acc, (&x, &y)| {
            acc + (f64::from(x) - f64::from(y)).powi(2)
        })
        .sqrt()
}

#[inline]
pub fn cosine<T>(a: &[T], b: &[T]) -> f64
where
    T: Copy,
    for<'a> ArrayView<'a, T, Ix1>: Dot<ArrayView<'a, T, Ix1>, Output = f64>,
{
    let x = ArrayView::from(a);
    let y = ArrayView::from(b);
    x.dot(&y) / (x.dot(&x) * y.dot(&y)).sqrt()
}

pub struct Model<T>
where
    T: Copy,
    f64: From<T>,
{
    /// Epsilon value - maximum distance between points in a cluster
    pub eps: f64,
    /// Minimum number of points in a cluster
    pub mpt: usize,

    distance: fn(a: &[T], b: &[T]) -> f64,
    c: Vec<Classification>,
    v: Vec<bool>,
}

impl<T> Model<T>
where
    T: Copy,
    f64: From<T>,
    for<'a> ArrayView<'a, T, Ix1>: Dot<ArrayView<'a, T, Ix1>, Output = f64>,
{
    /// Create a new `Model` with a set of parameters
    ///
    /// # Arguments
    /// * `eps` - maximum distance between datapoints within a cluster
    /// * `min_points` - minimum number of datapoints to make a cluster
    pub fn new(eps: f64, min_points: usize, mode: &str) -> Model<T> {
        Model {
            eps,
            mpt: min_points,
            c: Vec::new(),
            v: Vec::new(),
            distance: match mode {
                "euclidean" => euclidean_distance,
                "cosine" => cosine,
                _ => panic!("Unknown Mode {:?}", mode),
            },
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-02
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-07
    • 2018-05-09
    • 1970-01-01
    相关资源
    最近更新 更多