本文概述
- 特质论证
- 泛型函数的特质界限
- 特质实施规则
- 多重性状界限
- 默认方法
- 遗产
- Rust特质是Rust语言的一种功能, 它描述了它可以提供的每种类型的功能。
- 特质与其他语言中定义的接口的功能相似。
- 特征是一种将方法签名分组以定义一组行为的方法。
- 通过使用trait关键字定义特征。
trait trait_name{//body of the trait.}
在上述情况下, 我们声明特征, 后跟特征名称。在花括号内, 声明了方法签名以描述实现特征的类型的行为。
让我们看一个简单的例子:
struct Triangle{base : f64, height : f64, }trait HasArea{fn area(&
self)->
f64;
}impl HasArea for Triangle{fn area(&
self)->
f64{0.5*(self.base*self.height)}}fn main(){let a = Triangle{base:10.5, height:17.4};
let triangle_area = a.area();
println!("Area of a triangle is {}", triangle_area);
}
输出
Area of a triangle is 91.35
在上面的示例中, 声明了名为HasArea的特征, 其中包含area()函数的声明。 HasArea在类型Triangle上实现。通过使用结构实例即a.area()可以简单地调用area()函数。
特质论证性状还可以用作许多不同类型的参数。
上面的示例实现了HasArea特性, 其中包含area()函数的定义。我们可以定义调用area()函数的calculate_area()函数, 并使用实现HasArea特征的类型的实例来调用area()函数。
让我们看一下语法:
fn calculate_area(item : impl HasArea){println!("Area of the triangle is : {}", item.area());
}
泛型函数的特质界限特性非常有用, 因为它们描述了不同方法的行为。但是, 泛型函数不遵循此约束。让我们通过一个简单的场景来理解这一点:
fn calculate_area<
T>
( item : T){println!(?Area of a triangle is {}?, item.area());
}
在上述情况下, Rust编译器会引发” 找不到名为T类型的方法的错误” 。如果将特征绑定到通用T, 则可以克服以下错误:
fn calculate_area<
T : HasArea>
(item : T){println!("Area of a triangle is {} ", item.area());
}
在上述情况下, < T:HasArea> 表示” T可以是实现HasArea特性的任何类型” 。 Rust编译器知道, 任何实现HasArea特征的类型都将具有area()函数。
让我们看一个简单的例子:
trait HasArea{fn area(&
self)->
f64;
}struct Triangle{base : f64, height : f64, }impl HasArea for Triangle{fn area(&
self)->
f64{0.5*(self.base*self.height)}}struct Square{side : f64, }impl HasArea for Square{fn area(&
self)->
f64{self.side*self.side}}fn calculate_area<
T : HasArea>
(item : T){println!("Area is : {}", item.area());
}fn main(){let a = Triangle{base:10.5, height:17.4};
let b = Square{side : 4.5};
calculate_area(a);
calculate_area(b);
}
输出
Area is : 91.35Area is : 20.25
在上面的示例中, calculate_area()函数在” T” 上通用。
特质实施规则实现此特征有两个限制:
- 如果在你的范围中未定义特征, 则无法在任何数据类型上实现。
use::std::fs::File;
fn main(){let mut f = File::create("hello.txt");
let str = "srcmini";
let result = f.write(str);
}
输出
error : no method named 'write' found.let result = f.write(str);
在上述情况下, Rust编译器会抛出一个错误, 即use :: std :: fs :: File; ” 找不到名为’ write’ 的方法” ;名称空间不包含write()方法。因此, 我们需要使用Write特征来消除编译错误。
- 我们要实现的特征必须由我们定义。例如:如果定义HasArea特性, 则可以为i32类型实现此特性。但是, 我们无法实现Rust为i32类型定义的toString特性, 因为类型和特性均未在包装箱中定义。
- 使用” +” 运算符。
让我们看一个简单的例子:
use std::fmt::{Debug, Display};
fn compare_prints<
T: Debug + Display>
(t: &
T) { println!("Debug: '{:?}'", t);
println!("Display: '{}'", t);
}fn main() {let string = "srcmini";
compare_prints(&
string);
}
输出
Debug: ' "srcmini"'Display: ' srcmini'
在上面的示例中, 使用” +” 运算符将” 显示” 和” 调试” 特征限制为” T” 类型。
- 使用”
where”
子句。
- 可以使用出现在括号” {“ 之前的” where” 子句来编写边界。
- ‘ where’ 子句也可以应用于任意类型。
- 当使用’ where’ 子句时, 它使语法比普通语法更具表现力。
fn fun<
T: Display+Debug, V: Clone+Debug>
(t:T, v:V)->
i32{//block of code;
}
在上述情况下使用” where” 时:
fn fun<
T, V>
(t:T, v:V)->
i32where T : Display+ Debug, V : Clone+ Debug{//block of code;
}
在上述情况下, 使用” where” 子句的第二种情况使程序更具表现力和可读性。
让我们看一个简单的例子:
trait Perimeter{fn a(&
self)->
f64;
}struct Square{side : f64, }impl Perimeter for Square{fn a(&
self)->
f64{4.0*self.side}}struct Rectangle{ length : f64, breadth : f64, }impl Perimeter for Rectangle{ fn a(&
self)->
f64 {2.0*(self.length+self.breadth) }}fn print_perimeter<
Square, Rectangle>
(s:Square, r:Rectangle)where Square : Perimeter, Rectangle : Perimeter{let r1 = s.a();
let r2 = r.a();
println!("Perimeter of a square is {}", r1);
println!("Perimeter of a rectangle is {}", r2);
}fn main(){let sq = Square{side : 6.2};
let rect = Rectangle{length : 3.2, breadth:5.6};
print_perimeter(sq, rect);
}
输出
Perimeter of a square is 24.8Perimeter of a rectangle is 17.6
默认方法如果已知方法的定义, 则可以将默认方法添加到特征定义中。
我们看看吧:
trait Sample{ fn a(&
self);
fn b(&
self){println!("Print b");
} }
在上述情况下, 会将默认行为添加到特征定义。我们还可以覆盖默认行为。让我们通过一个例子看一下这种情况:
trait Sample{ fn a(&
self);
fn b(&
self) {println!("Print b");
} } struct Example{ a:i32, b:i32, }impl Sample for Example{fn a(&
self){println!("Value of a is {}", self.a);
}fn b(&
self){println!("Value of b is {}", self.b);
}}fn main(){let r = Example{a:5, b:7};
r.a();
r.b();
}
输出
Value of a is : 5Value of b is : 7
在上面的示例中, b()函数的行为在特征中定义。因此, 我们可以得出结论, 我们可以覆盖特征中定义的方法。
遗产从另一个特征派生的特征称为继承。有时, 有必要实现需要实现另一个特性的特性。如果我们想从” A” 特征中导出” B” 特征, 则它看起来像:
trait B : A;
让我们看一个简单的例子:
trait A{fn f(&
self);
}trait B : A{fn t(&
self);
}struct Example{first : String, second : String, }impl A for Example{fn f(&
self){ print!("{} ", self.first);
} } impl B for Example {fn t(&
self){print!("{}", self.second);
}}fn main(){let s = Example{first:String::from("srcmini"), second:String::from("tutorial")};
s.f();
s.t();
}
输出
srcmini tutorial
【Rust特质trait用法介绍】在上面的示例中, 我们的程序正在实现’ B’ 特性。因此, 它还需要实现” A” 特性。如果我们的程序未实现’ A’ 特征, 则Rust编译器将引发错误。
推荐阅读
- Rust智能指针解析
- 回收站删除的文件怎样恢复,图文详细说明回收站删除的文件怎样恢复
- 鼠标滚轮不能用,图文详细说明电脑鼠标滚轮不能用怎样办
- 无线网络设置,图文详细说明怎样设置无线网络连接
- 已停止此网站显示有安全证书出错的内容,图文详细说明已停止此网站显示有安全证书出错的内容怎样处理
- 0x000000EA,图文详细说明怎样处理0x000000EA
- 是否停止运行此脚本,图文详细说明怎样处理是否停止运行此脚本
- 电脑蓝屏代码0x000024,图文详细说明怎样处理电脑蓝屏代码0x000024
- dns服务器未响应,图文详细说明dns服务器未响应怎样处理