Rsut类型转换-From与Info
From与Info提供了一种显式的类型转换机制,Rust语言中不支持方法的重载和类的继承,在一些场景下可以使用From与Info达到方法重写和模拟类继承的目的。
问题描述
在GUI编程中,我们定义一个基础的Element结构体,用于描述画面上的元素,Button是Element的一个具体的实现,同时Button具有页面元素容器的功能,Button里面可以放Text和Img类型的页面元素,Text和Img都是是一种Element的具体实现, Element和Button的代码如下:
- Element结构体定义代码
pub struct Element{
// ...相关属性
}
- Button结构体定义代码
pub struct Button{
content:Element,
// ...相关属性
}
impl Button
{
pub fn new(content:Element)->Self{
Button{
// ...相关属性
content
}
}
}
- Text和Img
pub struct Img{
// 相关属性
}
pub struct Text{
// 相关属性
}
具体实现
在Rust中是没有继承概念的,所以Img和Text是不能继承Element。Button的new方法中,接收
Element类型的参数,也不能同时接收Img或Text类型的参数。该如何解决上述问题呢?这里就可以通过From和Into的方法来实现方法的重写和类继承的关系。
这里可以通过Info和From将Text和Img转换成Element类型,Button的new方法就可以接收Text类型或Img类型的实例。在Rust中,定义的类型都默认实现了Info trait,不用显式实现Info,所以将Img和Text类型绑定到Element的From trait上。
pub struct Img{
// 相关属性
}
impl From<Img> for Element{
fn from(img: Img) -> Self {
Element { }
}
}
pub struct Text{
// 相关属性
}
impl From<Text> for Element{
fn from(text: Text) -> Self {
Element { }
}
}
修过Button的相关定义
pub struct Button{
content:Element,
// ...相关属性
}
impl Button
{
pub fn new<E>(content:E)->Self
where E:Into<Element>
{
Button{
// ...相关属性
content:content.into()
}
}
}
这样Button的new方法就可以接收Img和Text类型的参数
let img = Img{};
let btn = Button::new(img);
let text = Text{};
let btn = Button::new(text);
该方式变相的实现了方法的重载,同时让Button、Text和Img与Element有了一种层级关系,逻辑上的一种继承关系,达到组织结构体的目的。上面的代码并没有使Text、Img与Element进行关联,让Text和Img可以当一种Element进行使用,需要使用Trait Object,类似Java中的多态。
- 1.首先定义一个trait,用于抽象Element的行为。
trait Widget{
fn draw(&self);
}
- 2.让Element拥有该行为
pub struct Element{
widget:Box<dyn Widget>,
// ...相关属性
}
// 对行为进行包装
impl Element{
fn draw(&self) {
self.widget.draw();
}
}
- 3.Text和Img实现trait
impl Widget for Img{
fn draw(&self) {
println!("This is img");
}
}
impl Widget for Text{
fn draw(&self) {
println!("This is text");
}
}
- 4.调整Text和Img的类型转换代码
impl From<Img> for Element{
fn from(img: Img) -> Self {
Element { widget: Box::new(img) }
}
}
impl From<Text> for Element{
fn from(text: Text) -> Self {
Element { widget: Box::new(text) }
}
}
- 5、最终Button代码的实现
pub struct Button{
pub content:Element,
// ...相关属性
}
impl Button
{
pub fn new<E>(content:E)->Self
where E:Into<Element>
{
Button{
// ...相关属性
content:content.into()
}
}
pub fn draw(&self){
self.content.draw()
}
}
测试代码
#[test]
fn test_button_new(){
let img = Img{};
let btn = Button::new(img);
btn.draw();
let text = Text{};
let btn = Button::new(text);
btn.draw();
}