- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在学习/试验生锈,在我在这门语言中发现的所有优雅中,有一个特点让我困惑,似乎完全不合适。
Rust在进行方法调用时自动取消指针的引用。我做了一些测试来确定具体的行为:
struct X { val: i32 }
impl std::ops::Deref for X {
type Target = i32;
fn deref(&self) -> &i32 { &self.val }
}
trait M { fn m(self); }
impl M for i32 { fn m(self) { println!("i32::m()"); } }
impl M for X { fn m(self) { println!("X::m()"); } }
impl M for &X { fn m(self) { println!("&X::m()"); } }
impl M for &&X { fn m(self) { println!("&&X::m()"); } }
impl M for &&&X { fn m(self) { println!("&&&X::m()"); } }
trait RefM { fn refm(&self); }
impl RefM for i32 { fn refm(&self) { println!("i32::refm()"); } }
impl RefM for X { fn refm(&self) { println!("X::refm()"); } }
impl RefM for &X { fn refm(&self) { println!("&X::refm()"); } }
impl RefM for &&X { fn refm(&self) { println!("&&X::refm()"); } }
impl RefM for &&&X { fn refm(&self) { println!("&&&X::refm()"); } }
struct Y { val: i32 }
impl std::ops::Deref for Y {
type Target = i32;
fn deref(&self) -> &i32 { &self.val }
}
struct Z { val: Y }
impl std::ops::Deref for Z {
type Target = Y;
fn deref(&self) -> &Y { &self.val }
}
#[derive(Clone, Copy)]
struct A;
impl M for A { fn m(self) { println!("A::m()"); } }
impl M for &&&A { fn m(self) { println!("&&&A::m()"); } }
impl RefM for A { fn refm(&self) { println!("A::refm()"); } }
impl RefM for &&&A { fn refm(&self) { println!("&&&A::refm()"); } }
fn main() {
// I'll use @ to denote left side of the dot operator
(*X{val:42}).m(); // i32::m() , Self == @
X{val:42}.m(); // X::m() , Self == @
(&X{val:42}).m(); // &X::m() , Self == @
(&&X{val:42}).m(); // &&X::m() , Self == @
(&&&X{val:42}).m(); // &&&X:m() , Self == @
(&&&&X{val:42}).m(); // &&&X::m() , Self == *@
(&&&&&X{val:42}).m(); // &&&X::m() , Self == **@
println!("-------------------------");
(*X{val:42}).refm(); // i32::refm() , Self == @
X{val:42}.refm(); // X::refm() , Self == @
(&X{val:42}).refm(); // X::refm() , Self == *@
(&&X{val:42}).refm(); // &X::refm() , Self == *@
(&&&X{val:42}).refm(); // &&X::refm() , Self == *@
(&&&&X{val:42}).refm(); // &&&X::refm(), Self == *@
(&&&&&X{val:42}).refm(); // &&&X::refm(), Self == **@
println!("-------------------------");
Y{val:42}.refm(); // i32::refm() , Self == *@
Z{val:Y{val:42}}.refm(); // i32::refm() , Self == **@
println!("-------------------------");
A.m(); // A::m() , Self == @
// without the Copy trait, (&A).m() would be a compilation error:
// cannot move out of borrowed content
(&A).m(); // A::m() , Self == *@
(&&A).m(); // &&&A::m() , Self == &@
(&&&A).m(); // &&&A::m() , Self == @
A.refm(); // A::refm() , Self == @
(&A).refm(); // A::refm() , Self == *@
(&&A).refm(); // A::refm() , Self == **@
(&&&A).refm(); // &&&A::refm(), Self == @
}
&self
声明的方法时(通过引用调用):
self
self
self
使用
T
(按值调用)声明的方法的行为与对于类型
&self
使用
&T
(按引用调用)声明并在对dot运算符左侧任何内容的引用上调用它们的行为类似。
Deref
trait的重载。
最佳答案
你的伪代码非常正确。对于这个例子,假设我们有一个方法调用foo.bar()
wherefoo: T
。我将使用fully qualified syntax(FQS)来明确调用方法的类型,例如A::bar(foo)
或A::bar(&***foo)
。我要写一堆随机的大写字母,每一个都是一些任意的类型/特征,除了T
总是调用方法的原始变量的类型。
算法的核心是:
对于每个"dereference step"foo
(即设置U
,然后设置U = T
,…)
如果有一个方法U = *T
其中接收器类型(方法中bar
的类型)与self
完全匹配,请使用它(a "by value method")
否则,添加一个auto ref(接受接收器的U
或&
),如果某个方法的接收器匹配&mut
,则使用它(an "autorefd method")
值得注意的是,每件事都考虑方法的“接收者类型”,而不是特征的&U
类型,即Self
在匹配方法时考虑impl ... for Foo { fn method(&self) {} }
,而&Foo
在匹配时考虑fn method2(&mut self)
。
如果在内部步骤中存在多个有效的trait方法(也就是说,在1的每个步骤中只能有零个或一个有效的trait方法),则这是一个错误。或者2,但是每个方法都有一个有效的:1中的一个优先),并且固有方法优先于特征方法。如果在循环结束时没有找到任何匹配的内容,这也是一个错误。递归&mut Foo
实现也是一个错误,它使循环无限(它们将达到“递归限制”)。
这些规则在大多数情况下似乎都是“我的意思”,尽管在某些边缘情况下,能够编写明确的FQS表单非常有用,对于宏生成的代码来说,这些规则也非常有用。
只添加了一个自动引用,因为
如果没有绑定,事情就会变得糟糕/缓慢,因为每种类型都可以有任意数量的引用
引用一个Deref
会保留与&foo
的强连接(它是foo
本身的地址),但如果引用更多则会失去它:foo
是堆栈上存储&&foo
的某个临时变量的地址。
实例
假设我们有一个调用&foo
,如果foo.refm()
具有类型:foo
,然后我们从X
开始,U = X
具有接收器类型refm
,因此步骤1不匹配,采用自动ref将给出&...
,并且这确实匹配(与&X
匹配),因此调用是Self = X
RefM::refm(&foo)
,以&X
开头,这与第一步中的U = &X
匹配(以&self
开头),因此调用是Self = X
RefM::refm(foo)
,这与两个步骤都不匹配(trait不是为&&&&&X
或&&&&X
实现的),因此我们取消引用一次以获取&&&&&X
,它与1匹配(与U = &&&&X
匹配),调用是Self = &&&X
RefM::refm(*foo)
与任一步骤都不匹配,因此它被取消引用一次,得到也不匹配的Z
,因此它被再次取消引用,得到不匹配1的Y
,但在自动定义后匹配,因此调用是X
。RefM::refm(&**foo)
,1。不匹配,2也不匹配。由于该特征不是针对&&A
(for 1)或&A
(for 2)实现的,因此它被解引用为&&A
,它与1.和&A
匹配
假设我们有Self = A
,而foo.m()
不是A
,如果Copy
有类型:foo
,然后A
直接与U = A
匹配,因此呼叫是self
与M::m(foo)
Self = A
,然后1。不匹配,2也不匹配。(既非&A
也非&A
实现特征),因此它被解引用到&&A
,它确实匹配,但A
要求按值取M::m(*foo)
,因此移出A
,因此产生错误。foo
,1。不匹配,但自动定义给出了&&A
,这是匹配的,因此调用是&&&A
与M::m(&foo)
的。
(此答案基于the code和is reasonably close to the (slightly outdated) README。这部分编译器/语言的主要作者Niko Matsakis也浏览了一下这个答案。)
关于reference - Rust的确切自动引用规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48070460/
通过多次搜索和pytorch文档本身,我可以发现在嵌入层内部有一个查找表,用于存储嵌入向量。我无法理解的是: 在这一层的培训期间究竟发生了什么? 权重是多少,以及这些权重的梯度是如何计算的? 我的直觉
当应用程序有大量数据(400M)要写入非阻塞套接字时,write() 返回EWOULDBLOCK 或EAGAIN 当发送缓冲区变满时。 当套接字被(e)轮询时,我有时会看到发送缓冲区中有 7M 空间(
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我经常阅读一些编程语言对模块的支持(“一流”)(OCaml,Scala,TypeScript [?]),并且最近偶然发现了这样的答案,即在Scala的显着特征中引用模块作为一流公民。 我以为我很清楚模
我已经提交了一个自定义的开放图表故事,但它被拒绝并显示以下消息: 打开图表捐赠(行动类型)提交内容、操作、对象和使用说明必须以英文提交。您可以在应用程序面板的“本地化”选项卡中翻译操作和对象。 如果我
给定一个任意的 boolean 值列表,确定其中一个恰好为真的最优雅的方法是什么? 最明显的 hack 是类型转换:将 false 转换为 0,将 true 转换为 1,然后对它们求和,并返回 sum
这个问题在这里已经有了答案: When to use extern "C" in simple words? [duplicate] (7 个答案) 关闭 9 年前。 如果您想将此问题标记为重复问题
我是一名优秀的程序员,十分优秀!