有的時候,可能希望使用的特質已經實現了其它特質(看後面可以知道,實際是要求相關類型實現了其它特質)。
RUST支持為特質(trait)指定限定的特質。
例如我們定義特質A,之後定義了類型T,這個時候還希望T已經實現了特質TC。
在rust中就是這個語法:
trait tx:t1
trait tx:t1+t2..+tn
根據相關數據的例子和説明,需要特別注意,具體的實現都是依賴於類型,而不是特質。
一、示例1
use std::fmt;
struct Point {
x: i32,
y: i32,
}
trait Copy{
fn copy(&self) -> Self;
}
trait OutlinePrint: fmt::Display+Copy{
fn outline_print(&self) {
let output = self.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {output} *");
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}
impl OutlinePrint for Point {}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl Copy for Point {
fn copy(&self) -> Self {
Point { x: self.x, y: self.y }
}
}
fn main() {
let p = Point { x: 10, y: 20 };
p.outline_print();
let c=p.copy();
c.outline_print();
}
在本例中Point必須實現特質Copy和Display和OutlinePrint,注意OutlinePrint的定義:
trait OutlinePrint: fmt::Display+Copy
多個特質之間用+號連接。
輸出如下:

二、示例2-在方法中使用特質有關方法
把以上的例子稍微修改下:
use std::fmt;
struct Point {
x: i32,
y: i32,
}
trait Copyable {
fn copy(&self) -> Self;
}
trait OutlinePrint: fmt::Display + Copyable +Sized{
fn outline_print(&self) {
// 先創建副本
let copied = self.copy();
// 然後將副本轉換為字符串
let output = copied.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {} *", output);
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}
impl OutlinePrint for Point {}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl Copyable for Point {
fn copy(&self) -> Self {
Point { x: self.x, y: self.y }
}
}
fn main() {
let p = Point { x: 10, y: 20 };
p.outline_print();
}
本例中,首先為OutlinePrint增加一個限定Sized,其次方法outline_print是先copy再to_string.
如果OutlinePrint不添加一個Sized,那麼會提示語句 let copied=self.copy()報錯:doesn't have a size known at compile-time
rustc的給出的建議是:fn outline_print(&self) where Self: Sized ,即為方法outline_print的參數添加限定(這是我們習慣的方式)
為什麼Point不需要實現Sized?這是因為Point的大小是確定的,其次編譯器會為此類類型隱式實現。
輸出略。
三、示例3-如果不使用特質的限定
由於可以為方法的參數進行限定,我們很容易想到其實可以只對參數限定即可。
為了節約篇幅,這裏只把核心的內容貼出:
trait OutlinePrint{
fn outline_print(&self)
where Self: fmt::Display + Copyable+Sized
{
// 先創建副本
let copied = self.copy();
// 然後將副本轉換為字符串
let output = copied.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {} *", output);
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}
輸出:

四、小結
這種定義方式個人認為不是很符合一般思維方式,這是因為明明是對類型的限制,但是這種限制確寫在特質上。
例如在java等語言中,就沒有這種方式。
個人更加傾向於採用示例3的方式,尤其是在接觸多了類似JAVA之類的OOP語言後。
當然rust這種定義方式也有優點:如果相關特質方法的參數都是這種要求,那麼寫在特質上,的確會少打一些字。
所以,rust程序員可以根據需要來決定限定方式,某種程度上rust為我們提供了方便性和靈活性。