【问题标题】:Specialise type for polymorphic type多态类型的特化类型
【发布时间】:2020-04-18 20:09:32
【问题描述】:

我正在学习 rust(来自 haskell 背景)。 而且我正在努力使用多态类型 - 在 haskell 中,我会使用类型孔/GHC 的类型推断来确定函数的返回类型是什么,我陷入了锈,专门化了一个泛型参数。

  • rustc:1.39.0
  • 货物:1.39.0
  • tui-库:0.8.0
  • 操作系统:linux mint

我目前的问题

假设我有一个描述番茄会话的类型(我将此数据存储在 sqllite-database 中)并且我想在 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 类型的东西。

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

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

我尝试在专用类型签名中插入不正确的类型

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

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

为了完整起见

为了方便调查: https://github.com/epsilonhalbe/pomodorust/tree/4f8c4929201ed90ddaef8af8d21076dbde78782b 是 github 上可以克隆和构建的项目的链接。我这里发的错误可以通过modyfingsrc/database.rs来重现编译失败

奖金:

如果在 haskell 中有相当于 _ 的东西可以告诉我 rust 编译器正在推断什么类型,那么我可以去挑选文档中的示例

let row_style = Style::default().fg(Color::White);
Table::new(
        ["Col1", "Col2", "Col3"].into_iter(),
        vec![
            Row::StyledData(["Row11", "Row12", "Row13"].into_iter(), row_style),
            Row::StyledData(["Row21", "Row22", "Row23"].into_iter(), row_style),
            Row::StyledData(["Row31", "Row32", "Row33"].into_iter(), row_style),
            Row::Data(["Row41", "Row42", "Row43"].into_iter())
        ].into_iter()
    )
    .block(Block::default().title("Table"))
    .header_style(Style::default().fg(Color::Yellow))
    .widths(&[Constraint::Length(5), Constraint::Length(5), Constraint::Length(10)])
    .style(Style::default().fg(Color::White))
    .column_spacing(1);

【问题讨论】:

  • 认为你想要的函数签名是pub fn as_row&lt;'a&gt;(self) -&gt; Row&lt;std::slice::Iter&lt;'a, String&gt;, &amp;'a String&gt; 虽然我很确定你会遇到一些生命周期问题,主要是你' 将有一个迭代器进入一个数组,该数组将在您从该函数返回的第二秒被删除。我对那里没有任何见解,但有人可能比我更有经验。

标签: rust type-inference


【解决方案1】:

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

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

任何需要将元素移出数组的实现,这会在数组中留下空洞,......如果在迭代期间发生恐慌,可能会导致坏事发生

...

我相信 Vec 会在出现恐慌的情况下通过泄漏内存来解决这个问题

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

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())
}

【讨论】:

    猜你喜欢
    • 2019-08-20
    • 2019-10-17
    • 2013-07-11
    • 2017-09-20
    • 2016-03-09
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多