当前位置: 首页 > news >正文

个人网站搭建wordpress专业做酒店装修的公司

个人网站搭建wordpress,专业做酒店装修的公司,网页制作代码模板,phpmyadmin做网站✨✨ 欢迎大家来到景天科技苑✨✨ #x1f388;#x1f388; 养成好习惯#xff0c;先赞后看哦~#x1f388;#x1f388; #x1f3c6; 作者简介#xff1a;景天科技苑 #x1f3c6;《头衔》#xff1a;大厂架构师#xff0c;华为云开发者社区专家博主#xff0c;… ✨✨ 欢迎大家来到景天科技苑✨✨ 养成好习惯先赞后看哦~ 作者简介景天科技苑 《头衔》大厂架构师华为云开发者社区专家博主阿里云开发者社区专家博主CSDN全栈领域优质创作者掘金优秀博主51CTO博客专家等。 《博客》Rust开发Python全栈Golang开发云原生开发PyQt5和Tkinter桌面开发小程序开发人工智能js逆向App逆向网络系统安全数据分析Djangofastapiflask等框架云原生K8Slinuxshell脚本等实操经验网站搭建数据库等分享。 所属的专栏Rust语言通关之路 景天的主页景天科技苑 文章目录 Rust trait高级用法一、Trait基础回顾1.1 Trait定义与实现1.2 Trait作为参数1.3 Trait作为返回类型 二、关联类型(Associated Types)三、默认泛型类型参数和运算符重载四、完全限定语法与消歧义调用相同名称的方法五、父 trait 用于在另一个 trait 中使用某 trait 的功能六、newtype 模式用于在外部类型上实现外部 trait Rust trait高级用法 Rust语言中的trait是其类型系统的核心特性之一它提供了定义共享行为的强大机制。 对于初学者来说trait类似于其他语言中的接口但实际上Rust的trait功能要强大得多。 本文将深入探讨trait的高级用法通过实际案例展示如何充分利用这一特性来编写灵活、可重用且类型安全的Rust代码。 一、Trait基础回顾 在深入高级用法之前让我们先简要回顾trait的基本概念。 1.1 Trait定义与实现 // 定义一个简单的trait trait Greet {fn greet(self) - String; }// 为具体类型实现trait struct Person {name: String, }impl Greet for Person {fn greet(self) - String {format!(Hello, my name is {}, self.name)} }1.2 Trait作为参数 fn print_greetingT: Greet(item: T) {println!({}, item.greet()); }1.3 Trait作为返回类型 fn create_greeter(name: String) - impl Greet {Person { name } }二、关联类型(Associated Types) 关联类型是trait定义中的占位符类型允许在实现trait时指定具体类型。 关联类型associated types是一个将类型占位符与 trait 相关联的方式这样 trait 的方法签名中就可以使用这些占位符类型。 trait 的实现者会针对特定的实现在这个类型的位置指定相应的具体类型。如此可以定义一个使用多种类型的 trait直到实现此 trait 时都无需知道这些类型具体是什么。 一个带有关联类型的 trait 的例子是标准库提供的 Iterator trait。它有一个叫做 Item 的关联类型来替代遍历的值的类型。 pub trait Iterator {type Item;fn next(mut self) - OptionSelf::Item; }Item 是一个占位类型同时 next 方法定义表明它返回 OptionSelf::Item 类型的值。 这个 trait 的实现者会指定 Item 的具体类型然而不管实现者指定何种类型, next 方法都会返回一个包含了此具体类型值的 Option。 关联类型看起来像一个类似泛型的概念因为它允许定义一个函数而不指定其可以处理的类型。那么为什么要使用关联类型呢 让我们通过一个Counter 结构体上实现 Iterator trait 的例子来检视其中的区别。在如下示例中指定了 Item 的类型为 u32 trait Iterator {type Item; // 关联类型定义的时候无需知道具体是什么类型fn next(mut self) - OptionSelf::Item; }struct Counter {count: u32, }impl Iterator for Counter {type Item u32; // 指定关联类型的具体类型实现的时候才需要指定具体类型fn next(mut self) - OptionSelf::Item {if self.count 5 {self.count 1;Some(self.count)} else {None}} }fn main() {let mut counter Counter { count: 0 };while let Some(value) counter.next() {println!(count: {}, value);} }为啥不使用泛型 这类似于泛型。那么为什么 Iterator trait 不像如下示例那样定义呢 pub trait IteratorT {fn next(mut self) - OptionT; }区别在于当使用泛型时则不得不在每一个实现中标注类型。 这是因为我们也可以实现为 IteratorString for Counter或任何其他类型这样就可以有多个 Counter 的 Iterator 的实现。 换句话说当 trait 有泛型参数时可以多次实现这个 trait每次需改变泛型参数的具体类型。 接着当使用 Counter 的 next 方法时必须提供类型标注来表明希望使用 Iterator 的哪一个实现。 当然非要通过泛型也可以实现结构体也设置成泛型 //泛型实现 struct Counter2T {count: T, }trait Iterator2T {fn next(mut self) - OptionT; }impl Iterator2i32 for Counter2i32 {fn next(mut self) - Optioni32 {if self.count 5 {self.count 1;Some(self.count)} else {None}} }impl Iterator2f32 for Counter2f32 {fn next(mut self) - Optionf32 {if self.count 5.0 {self.count 1.0;Some(self.count)} else {None}} }impl Iterator2String for Counter2String {fn next(mut self) - OptionString {if self.count.len() 5 {self.count.push(a);Some(self.count.clone())} else {None}} }fn main() {let mut counter2 Counter2 { count: 0 };while let Some(value) counter2.next() {println!(count: {}, value);}let mut counter3 Counter2 { count: 0.0 };while let Some(value) counter3.next() {println!(count: {}, value);}let mut counter4 Counter2 { count: String::from(a) };while let Some(value) counter4.next() {println!(count: {}, value);} }通过关联类型则无需标注类型因为不能多次实现这个 trait。 对于使用关联类型的定义我们只能选择一次 Item 会是什么类型因为只能有一个 impl Iterator for Counter。 当调用 Counter 的 next 时不必每次指定我们需要 u32 值的迭代器。 三、默认泛型类型参数和运算符重载 当使用泛型类型参数时可以为泛型指定一个默认的具体类型。 如果默认类型就足够的话这消除了为具体类型实现 trait 的需要。为泛型类型指定默认类型的语法是在声明泛型类型时使用 PlaceholderTypeConcreteType。 类似这样 这种情况的一个非常好的例子是用于运算符重载。运算符重载Operator overloading是指在特定情况下自定义运算符比如 行为的操作。 Rust 并不允许创建自定义运算符或重载任意运算符不过 std::ops 中所列出的运算符 和相应的 trait 可以通过实现运算符相关 trait 来重载。 例如如下示例中展示了如何在 Point 结构体上实现 Add trait 来重载 运算符这样就可以将两个 Point 实例相加了 use std::ops::Add;#[derive(Debug, PartialEq)] struct Point {x: i32,y: i32, }//这里不指定Add类型默认是Self也就是Point类型 impl Add for Point {type Output Point; //指定关联类型为我们定义的Point类型fn add(self, other: Point) - Point {Point {x: self.x other.x,y: self.y other.y,}} }fn main() {//运用加法println!({:?}, Point { x: 1, y: 0 } Point { x: 2, y: 3 }); }add 方法将两个 Point 实例的 x 值和 y 值分别相加来创建一个新的 Point。Add trait 有一个叫做 Output 的关联类型它用来决定 add 方法的返回值类型。 这里默认泛型类型位于 Add trait 中。这里是其定义 这看来应该很熟悉这是一个带有一个方法和一个关联类型的 trait。 比较陌生的部分是尖括号中的 RHSSelf这个语法叫做 默认类型参数default type parameters。 RHS 是一个泛型类型参数“right hand side” 的缩写它用于定义 add 方法中的 rhs 参数的类型。 如果实现 Add trait 时不指定 RHS 的具体类型RHS 的类型将是默认的 Self 类型也就是在其上实现 Add 的类型。 当为 Point 实现 Add 时使用了默认的 RHS因为我们希望将两个 Point 实例相加。让我们看看一个实现 Add trait 时希望自定义 RHS 类型而不是使用默认类型的例子。 这里有两个存放不同单元值的结构体Millimeters 和 Meters。我们希望能够将毫米值与米值相加并让 Add 的实现正确处理转换。 可以为 Millimeters 实现 Add 并以 Meters 作为 RHS其实就是指定相加的两个数右边的类型为Meters 如下示例 所示。 use std::ops::Add;//定义毫米和米 #[derive(Debug)] struct Millimeters(u32); #[derive(Debug)] struct Meters(u32);//为Millimeters实现Add trait //指定other为Meters类型 impl AddMeters for Millimeters {type Output Millimeters;fn add(self, other: Meters) - Millimeters {Millimeters(self.0 other.0 * 1000)} }fn main() {let m Millimeters(100);let n Meters(1);//注意: 这两个类型相加位置不能颠倒因为我们为Millimeters实现了AddMeters而不是AddMillimeters// let result n m; //报错 cannot add Millimeters to Meterslet result m n;println!(Result: {:?}, result); }毫米加米得到毫米 为了使 Millimeters 和 Meters 能够相加我们指定 impl Add 来设定 RHS 类型参数的值而不是使用默认的 Self。 默认参数类型主要用于如下两个方面 扩展类型而不破坏现有代码。在大部分用户都不需要的特定情况进行自定义。 标准库的 Add trait 就是一个第二个目的例子大部分时候你会将两个相似的类型相加不过它提供了自定义额外行为的能力。 在 Add trait 定义中使用默认类型参数意味着大部分时候无需指定额外的参数。 换句话说一小部分实现的样板代码是不必要的这样使用 trait 就更容易了。 第一个目的是相似的但过程是反过来的如果需要为现有 trait 增加类型参数为其提供一个默认类型将允许我们在不破坏现有实现代码的基础上扩展 trait 的功能。 四、完全限定语法与消歧义调用相同名称的方法 Rust 既不能避免一个 trait 与另一个 trait 拥有相同名称的方法也不能阻止为同一类型同时实现这两个 trait。甚至直接在类型上实现开始已经有的同名方法也是可能的 不过当调用这些同名方法时需要告诉 Rust 我们希望使用哪一个。 考虑如下示例中的代码这里定义了 trait Pilot 和 Wizard 都拥有方法 fly。 接着在一个本身已经实现了名为 fly 方法的类型 Human 上实现这两个 trait。每一个 fly 方法都进行了不同的操作 对于方法的完全限定调用 trait Pilot {fn fly(self); }trait Wizard {fn fly(self); }struct Human;impl Pilot for Human {fn fly(self) {println!(This is your captain speaking.);} }impl Wizard for Human {fn fly(self) {println!(Up!);} }impl Human {fn fly(self) {println!(*waving arms furiously*);} }//当调用 Human 实例的 fly 时编译器默认调用直接实现在类型上的方法 fn main() {let person Human;//human实例直接调用fly方法会调用impl Human中的fly方法而不是Pilot和Wizard中的fly方法person.fly(); }这表明 Rust 调用了直接实现在 Human 上的 fly 方法。 完全限定语法调用具体的方法 为了能够调用 Pilot trait 或 Wizard trait 的 fly 方法我们需要使用更明显的语法以便能指定我们指的是哪个 fly 方法。这个语法展示在如下示例中 fn main() {let person Human;//human实例直接调用fly方法会调用impl Human中的fly方法而不是Pilot和Wizard中的fly方法person.fly();//使用完全限定语法来调用Pilot和Wizard中的fly方法Pilot::fly(person);Wizard::fly(person); }在方法名前指定 trait 名向 Rust 澄清了我们希望调用哪个 fly 实现。也可以选择写成 Human::fly(person)这等同于person.fly()不过如果无需消歧义的话这么写就有点长了。 对于关联函数的完全限定调用(没有self参数) 因为 fly 方法获取一个 self 参数如果有两个 类型 都实现了同一 traitRust 可以根据 self 的类型计算出应该使用哪一个 trait 实现。 然而关联函数是 trait 的一部分但没有 self 参数。 当同一作用域的两个类型实现了同一 traitRust 就不能计算出我们期望的是哪一个类型除非使用 完全限定语法fully qualified syntax。 例如如下示例中的 Animal trait 来说它有关联函数 baby_name结构体 Dog 实现了 Animal同时有关联函数 baby_name 直接定义于 Dog 之上 trait Animal {fn baby_name() - String; }struct Dog;impl Dog {fn baby_name() - String {String::from(Spot)} }impl Animal for Dog {fn baby_name() - String {String::from(puppy)} }fn main() {println!(A baby dog is called {}, Dog::baby_name()); }这段代码用于一个动物收容所他们将所有的小狗起名为 Spot这实现为定义于 Dog 之上的关联函数 baby_name。 Dog 类型还实现了 Animal trait它描述了所有动物的共有的特征。小狗被称为 puppy这表现为 Dog 的 Animal trait 实现中与 Animal trait 相关联的函数 baby_name。 在 main 调用了 Dog::baby_name 函数它直接调用了定义于 Dog 之上的关联函数。这段代码会打印出 这并不是我们需要的。我们希望调用的是 Dog 上 Animal trait 实现那部分的 baby_name 函数这样能够打印出 A baby dog is called puppy。 如果将 main 改为在方法前面加上trait的方式则会得到一个编译错误 因为 Animal::baby_name 是关联函数而不是方法因此它没有 self 参数Rust 无法计算出所需的是哪一个 Animal::baby_name 实现。我们会得到这个编译错误 为了消歧义并告诉 Rust 我们希望使用的是 Dog 的 Animal 实现需要使用 完全限定语法这是调用函数时最为明确的方式。如下示例展示了如何使用完全限定语法 fn main() {//使用完全限定语法来调用Dog实现Animal trait的baby_name方法println!(A baby dog is called {}, Dog as Animal::baby_name()); }我们在尖括号中向 Rust 提供了类型标注并通过在此函数调用中将 Dog 类型当作 Animal 对待来指定希望调用的是 Dog 上 Animal trait 实现中的 baby_name 函数。 现在这段代码会打印出我们期望的数据 通常完全限定语法定义为 Type as Trait::function(receiver_if_method, next_arg, ...);对于关联函数其没有一个 receiver故只会有其他参数的列表。可以选择在任何函数或方法调用处使用完全限定语法。 然而允许省略任何 Rust 能够从程序中的其他信息中计算出的部分。只有当存在多个同名实现而 Rust 需要帮助以便知道我们希望调用哪个实现时才需要使用这个较为冗长的语法。 五、父 trait 用于在另一个 trait 中使用某 trait 的功能 有时我们可能会需要某个 trait 使用另一个 trait 的功能。 在这种情况下需要能够依赖相关的 trait 也被实现。这个所需的 trait 是我们实现的 trait 的 父超 traitsupertrait。 语法 trait1: trait2 trait1就是子trait, trait2是父trait 要求实现子 trait 的类型必须实现所有 supertrait。在 Rust 中被继承的 trait 称为 supertrait。实现子 trait 时必须已经实现了所有 supertrait 例如我们希望创建一个带有 outline_print 方法的 trait OutlinePrint它会打印出带有星号框的值。 也就是说如果 Point 实现了 Display 并返回 (x, y)调用以 1 作为 x 和 3 作为 y 的 Point 实例的 outline_print 会显示如下 实现Display只需要实现fmt方法 //子trait父trait use std::fmt::Display;//自定义OutlinePrint trait 继承Display trait要求实现Display trait trait OutlinePrint: Display {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));} }struct Point {x: i32,y: i32, }//为Point实现Display trait只需要实现fmt方法 impl Display for Point {fn fmt(self, f: mut std::fmt::Formatter_) - std::fmt::Result {write!(f, ({}, {}), self.x, self.y)} }impl OutlinePrint for Point {}fn main() {let p Point { x: 1, y: 3 };p.outline_print(); }六、newtype 模式用于在外部类型上实现外部 trait 之前我们提到了孤儿规则orphan rule它说明只要 trait 或类型对于当前 crate 在本地的话就可以在此类型上实现该 trait。 一个绕开这个限制的方法是使用 newtype 模式newtype pattern它涉及到在一个元组结构体中创建一个新类型。 这个元组结构体带有一个字段作为希望实现 trait 的类型的简单封装。 接着这个封装类型对于 crate 是本地的这样就可以在这个封装上实现 trait。 Newtype 是一个源自 Haskell 编程语言的概念。使用这个模式没有运行时性能消耗这个封装类型在编译时就被省略了。 例如如果想要在 VecT 上实现 Display而孤儿规则阻止我们直接这么做因为 Display trait 和 VecT 都定义于我们的 crate 之外。 可以创建一个包含 VecT 实例的 Wrapper 结构体接着可以如下示例 那样在 Wrapper 上实现 Display 并使用 VecT 的值 //外部类型实现外部trait use std::fmt;//创建一个包含外部类型Vec的元组结构体Wrapper struct Wrapper(VecString);//为Wrapper实现Display trait impl fmt::Display for Wrapper {fn fmt(self, f: mut fmt::Formatter) - fmt::Result {//以逗号相连成[]包裹的字符串write!(f, [{}], self.0.join(, ))} }fn main() {let w Wrapper(vec![String::from(hello), String::from(world)]);println!(w {}, w); }Display 的实现使用 self.0 来访问其内部的 Vec因为 Wrapper 是元组结构体而 Vec 是结构体总位于索引 0 的项。接着就可以使用 Wrapper 中 Display 的功能了。 此方法的缺点是因为 Wrapper 是一个新类型它没有定义于其值之上的方法 必须直接在 Wrapper 上实现 Vec 的所有方法这样就可以代理到self.0 上 —— 这就允许我们完全像 Vec 那样对待 Wrapper。 如果希望新类型拥有其内部类型的每一个方法为封装类型实现 Deref trait 并返回其内部类型是一种解决方案。 如果不希望封装类型拥有所有内部类型的方法 —— 比如为了限制封装类型的行为 —— 则必须只自行实现所需的方法。
http://www.zqtcl.cn/news/27683/

相关文章:

  • 门户网站直接登录系统珠海有什么好的网站推广公司
  • 海口模板网站建站化妆品备案查询
  • 寻亲网站开发设计文档河南洛阳网站建设
  • 个人可以建门户网站吗餐饮网站源码
  • 企业网站建设多少家网上商城平台运营方案
  • 爱站工具包手机版外包做网站的会给你什么
  • 视频网站做电商wordpress评论美化
  • 梁山网站建设公司网站设计师是什么
  • 电商网店开店全过程郑州网站排名优化
  • 潍坊网站建设推广公司牛天下网站做的怎么样
  • wordpress首页是什么广州推广seo
  • 宁波网站建设地址05网数学书答案
  • 个人网站建站源码做网站需要阿里云吗
  • 上海浦东建设集团官方网站私人诊所网站源码
  • 新材料 东莞网站建设郑州影视公司有哪些
  • 做U启的网站免费行情网站大全下载
  • 成都手机端建站模板注册的网站
  • 专业的高密网站建设建一个app平台的费用多少
  • 自己做网站 搜索功能开发线上商城怎么推广
  • 微网站模板制作教程dw怎么做音乐网站
  • 网站后台管理优化百度收录的网站标题 --
  • 网站架构建设方案想要黑掉一个网站 要怎么做
  • seo网站优化方案案例友情链接英语
  • 兰州企业网站建设哪家好成都十大平面设计公司
  • 一学一做腾讯视频网站吗台州网站制作套餐
  • 单位网站建设需要哪些技术王占山将军简介
  • asp网站栏目修改营销管理网站
  • 根据网站集约化建设要求网站的外部链接怎么做
  • 宁波网站制作联系方式注册网站不需要手机验证的
  • 鞍山做网站优化国外家居设计网站