- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在试图更好地理解 Any
特性时,我看到它 has an impl
block for the trait itself .我不明白这个构造的目的,或者即使它有一个特定的名称。
我用“普通”特性方法和 impl
block 中定义的方法做了一个小实验:
trait Foo {
fn foo_in_trait(&self) {
println!("in foo")
}
}
impl dyn Foo {
fn foo_in_impl(&self) {
println!("in impl")
}
}
impl Foo for u8 {}
fn main() {
let x = Box::new(42u8) as Box<dyn Foo>;
x.foo_in_trait();
x.foo_in_impl();
let y = &42u8 as &dyn Foo;
y.foo_in_trait();
y.foo_in_impl(); // May cause an error, see below
}
Editor's note
In versions of Rust up to and including Rust 1.15.0, the line
y.foo_in_impl()
causes the error:error: borrowed value does not live long enough
--> src/main.rs:20:14
|
20 | let y = &42u8 as &Foo;
| ^^^^ does not live long enough
...
23 | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime...This error is no longer present in subsequent versions, but the concepts explained in the answers are still valid.
从这个有限的实验来看,impl
block 中定义的方法似乎比 trait
block 中定义的方法更具限制性。这样做可能会解锁一些额外的东西,但我还不知道它是什么! ^_^
来自 The Rust Programming Language 的部分 traits和 trait objects不要提这个。搜索 Rust 源代码本身,似乎只有 Any
和 Error
使用此特定功能。在我查看源代码的少数 crate 中,我没有看到它被使用过。
最佳答案
当您定义名为 Foo
的特征时可以变成一个对象,Rust 还定义了一个名为 dyn Foo
的特征对象类型。 .在旧版本的 Rust 中,这种类型只被称为 Foo
(参见 What does "dyn" mean in a type?)。为了向后兼容这些旧版本,Foo
尽管 dyn
仍然可以命名特征对象类型语法应该用于新代码。
Trait 对象有一个生命周期参数,它指定了实现者生命周期参数中最短的一个。要指定该生命周期,您可以将类型写为 dyn Foo + 'a
.
当你写 impl dyn Foo {
(或者只是 impl Foo {
使用旧语法),您没有指定该生命周期参数,它默认为 'static
. y.foo_in_impl();
上编译器的注释声明暗示:
note: borrowed value must be valid for the static lifetime...
我们要做的就是编写一个通用的 impl
来让它变得更加宽松。在任何一生中:
impl<'a> dyn Foo + 'a {
fn foo_in_impl(&self) { println!("in impl") }
}
现在,请注意 self
关于 foo_in_impl
的争论是一个借用的指针,它有自己的生命周期参数。 self
的类型,完整形式看起来像 &'b (dyn Foo + 'a)
(由于运算符优先级,括号是必需的)。 Box<u8>
拥有它的 u8
– 它不借用任何东西 –,所以你可以创建一个 &(dyn Foo + 'static)
从它出来。另一方面,&42u8
创建一个 &'b (dyn Foo + 'a)
其中 'a
不是 'static
,因为 42u8
放在栈上的一个隐藏变量中,trait对象借用这个变量。 (虽然这并没有什么意义;u8
没有借用任何东西,所以它的 Foo
实现应该总是与 dyn Foo + 'static
兼容 ... 42u8
是从堆栈中借用的事实应该影响'b
,而不是 'a
。)
另一件需要注意的事情是特征方法是多态的,即使它们有一个默认实现并且它们没有被覆盖,而特征对象的固有方法是单态的(只有一个函数,无论特征背后是什么) .例如:
use std::any::type_name;
trait Foo {
fn foo_in_trait(&self)
where
Self: 'static,
{
println!("{}", type_name::<Self>());
}
}
impl dyn Foo {
fn foo_in_impl(&self) {
println!("{}", type_name::<Self>());
}
}
impl Foo for u8 {}
impl Foo for u16 {}
fn main() {
let x = Box::new(42u8) as Box<dyn Foo>;
x.foo_in_trait();
x.foo_in_impl();
let x = Box::new(42u16) as Box<Foo>;
x.foo_in_trait();
x.foo_in_impl();
}
示例输出:
u8
dyn playground::Foo
u16
dyn playground::Foo
在 trait 方法中,我们得到了底层类型的类型名称(这里是 u8
或 u16
),所以我们可以得出 &self
的类型将因一个实现者而异(它将是 &u8
对于 u8
实现者和 &u16
对于 u16
实现者——不是特征对象)。然而,在固有方法中,我们得到了类型名称dyn Foo
。 ( + 'static
), 所以我们可以得出结论 &self
的类型总是 &dyn Foo
(特征对象)。
关于rust - 为什么我要在特征上而不是作为特征的一部分来实现方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53997145/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!