如何消除这段Rust代码中的重复逻辑?
如何消除Rust GTK代码中的重复逻辑
我有一段可正常运行但存在重复逻辑的Rust GTK代码:
fn append_column(tree: &TreeView, attribute: &str, id: i32) { let column = TreeViewColumn::new(); match attribute { "text" => { let cell = CellRendererText::new(); TreeViewColumnExt::pack_start(&column, &cell, true); TreeViewColumnExt::add_attribute(&column, &cell, attribute, id); } "pixbuf" => { let cell = CellRendererPixbuf::new(); TreeViewColumnExt::pack_start(&column, &cell, true); TreeViewColumnExt::add_attribute(&column, &cell, attribute, id); } _ => { panic!("Unexpected attribute") } } tree.append_column(&column); }
我尝试用downcast()简化代码,结果运行报错:
fn append_column(tree: &TreeView, attribute: &str, id: i32) { let column = TreeViewColumn::new(); let cell : CellRenderer; match attribute { "text" => { cell = CellRendererText::new().downcast::<CellRenderer>().unwrap() } "pixbuf" => { cell = CellRendererPixbuf::new().downcast::<CellRenderer>().unwrap() } _ => { panic!("Unexpected attribute") } } TreeViewColumnExt::pack_start(&column, &cell, true); TreeViewColumnExt::add_attribute(&column, &cell, attribute, id); tree.append_column(&column); }
错误信息:
error[E0277]: the trait bound `CellRenderer: IsA<CellRendererText>` is not satisfied --> src/main.rs:23:52 | 23 | "text" => { cell = CellRendererText::new().downcast::<CellRenderer>().unwrap() } | ^^^^^^^^ the trait `IsA<CellRendererText>` is not implemented for `CellRenderer`
请问该怎么消除这段代码里的重复逻辑?
解决方法:利用AsRef<CellRenderer>特性
GTK的CellRendererText和CellRendererPixbuf都实现了AsRef<CellRenderer>,不需要用downcast,可以通过提取通用逻辑来消除重复:
方案1:用闭包复用处理逻辑
use gtk::{CellRenderer, CellRendererPixbuf, CellRendererText, TreeView, TreeViewColumn, TreeViewColumnExt}; fn append_column(tree: &TreeView, attribute: &str, id: i32) { let column = TreeViewColumn::new(); // 把重复的单元格操作封装成闭包 let setup_cell = |cell: &impl AsRef<CellRenderer>| { TreeViewColumnExt::pack_start(&column, cell.as_ref(), true); TreeViewColumnExt::add_attribute(&column, cell.as_ref(), attribute, id); }; match attribute { "text" => setup_cell(&CellRendererText::new()), "pixbuf" => setup_cell(&CellRendererPixbuf::new()), _ => panic!("Unexpected attribute"), } tree.append_column(&column); }
方案2:封装单元格创建逻辑
use gtk::{CellRenderer, CellRendererPixbuf, CellRendererText, TreeView, TreeViewColumn, TreeViewColumnExt}; // 单独封装单元格创建函数,返回实现AsRef<CellRenderer>的类型 fn create_cell(attribute: &str) -> Box<dyn AsRef<CellRenderer>> { match attribute { "text" => Box::new(CellRendererText::new()), "pixbuf" => Box::new(CellRendererPixbuf::new()), _ => panic!("Unexpected attribute"), } } fn append_column(tree: &TreeView, attribute: &str, id: i32) { let column = TreeViewColumn::new(); let cell = create_cell(attribute); TreeViewColumnExt::pack_start(&column, cell.as_ref(), true); TreeViewColumnExt::add_attribute(&column, cell.as_ref(), attribute, id); tree.append_column(&column); }
原代码报错原因
downcast是用于将父类型向下转换为子类型的方法,而你需要的是把子类型(CellRendererText)向上转换为父类型(CellRenderer)——这一步GTK已经通过IsA trait自动支持,直接传递子类型引用即可,完全不需要调用downcast。
内容的提问来源于stack exchange,提问作者DobbyTheElf
相关产品推荐
相关产品推荐

