专用于多态类型

时间:2019-12-30 01:19:55

标签: rust type-inference

我正在学习生锈(来自haskell背景)。 而且我正在努力使用多态类型-在haskell中,我将使用Holes / GHC类型推断来确定函数的返回类型被卡在rust中,以专门化泛型参数。

  • rustc :1.39.0
  • 货物:1.39.0
  • tui -库:0.8.0
  • os :Linux薄荷

我当前的问题

说我有一个描述Pomodoro会话的类型(我将这些数据存储在sqllite数据库中),并且我想在tui-table中显示这些数据

use tui::widgets::Row;

pub struct Pom {
    pub id: i32,
    pub duration: i64,
    pub ticket_id: Option<String>,
    pub note: Option<String>,
}

impl Pom {
    pub fn as_row(self) -> ? {
        let ret : [String; 4] = [
            format!("{}", self.id),
            format!("{}", self.duration),
            self.ticket_id.unwrap_or(String::new()),
            self.note.unwrap_or(String::new()),
        ];
        Row::Data(ret.into_iter())
    }
}

当我将?替换为i32(如{How do I print the type of a variable in Rust?中的建议)时,编译器非常有帮助,它告诉我它期望的类型为Row。 / p>

我知道Row是一个具有以下定义的枚举:

pub enum Row<D, I> where
    D: Iterator<Item = I>,
    I: Display,  {
    Data(D),
    StyledData(D, Style),
}

我试图将不正确的类型插入专用类型签名中

pub fn as_row(self) -> Row<?,?> {

即再次,编译器告诉我?不是迭代器,但是我不知道如何进一步专门化。

出于完整性考虑

为了便于调查,请按以下步骤操作: https://github.com/epsilonhalbe/pomodorust/tree/4f8c4929201ed90ddaef8af8d21076dbde78782b是指向github上可克隆和构建的项目的链接。我在这里发布的错误可以通过修改i32来重现,以使编译失败

奖金:

如果haskell中有等同于i32的内容可以告诉我rust编译器推断的是哪种类型,那么我可以将文档中的示例拆开

src/database.rs

1 个答案:

答案 0 :(得分:4)

@kopecs是正确的。 Row<std::slice::Iter<'a, String>, &'a String>是正确的返回类型,但正如他们所解释的那样,由于它将返回对局部变量的引用,因此会导致生命周期问题。

tui::widgets::Row要求其类型DIterator。使用数组和数组上的into_iter的问题是IntoIterator仅是"implemented for &[T; N] and &mut [T; N]",即引用。最好用this Reddit thread

来解释
  

任何此类需要将元素移出数组的实现都会在数组中留下漏洞,...如果在迭代过程中发生紧急情况,可能会导致发生坏事

     

...

     

我认为Vec在出现紧急情况时会通过泄漏内存来解决此问题

无论如何,解决此问题的一种方法是只使用Vec而不是数组。然后,您的迭代器可以拥有字符串,而不是仅在原始数组中保留对字符串的引用。固定方法如下:

pub fn as_row(self) -> Row<impl Iterator<Item=String>, String> {  // <-- correct return type
    let ret = vec![  // <-- use a Vec
        format!("{}", self.id),
        format!("{}", self.duration),
        self.ticket_id.unwrap_or(String::new()),
        self.note.unwrap_or(String::new()),
    ];
    Row::Data(ret.into_iter())
}