- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
关闭。这个问题是opinion-based .它目前不接受答案。
想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.
9 天前关闭。
Improve this question
我发现自己编写的函数接受参数为 Borrow<T>
以便它透明地接受值和引用。
例子:
use std::borrow::Borrow;
#[derive(Debug, Copy)]
struct Point {
pub x: i32,
pub y: i32,
}
pub fn manhattan<T, U>(p1: T, p2: U) -> i32
where
T: Borrow<Point>,
U: Borrow<Point>,
{
let p1 = p1.borrow();
let p2 = p2.borrow();
(p1.x - p2.x + p1.y - p2.y).abs()
}
这对于实现
std:ops
很有用喜欢
Add
,否则将需要大量重复以透明地支持引用。
最佳答案
我认为这个问题有两个部分。
1.是Borrow
trait 在 Rust 中抽象所有权的惯用方式?
是 .如果您打算编写一个接受 Foo
的函数或 &Foo
, F: Borrow<Foo>
是使用的权利。 AsRef
另一方面,通常只为类似引用的东西实现,而不是为拥有的值实现。
2. 在 Rust 中抽象所有权是惯用的吗?
有时 .这是一个有趣的问题,因为像 manhattan
这样的函数之间存在微妙但重要的区别。以及如何Borrow
是惯用的。
在 Rust 中,函数是需要拥有它的参数还是仅仅借用它们是函数接口(interface)的重要组成部分。通常,Rustaceans 不介意写作 &
在函数调用中,因为它是关于被调用函数的相关语义事实的句法标记。一个可以接受 Point
的函数或 &Point
不比只能接受的更普遍有用&Point
: 如果你有 Point
,您所要做的就是借用它。所以使用更简单的签名是惯用的,它最准确地记录了函数真正需要的类型:&Point
.
可是等等!这些接受论点的方式之间还存在其他差异。一个区别是调用开销:a &Point
通常会在单个指针大小的寄存器中传递,而 Point
可以在多个寄存器或堆栈上传递,具体取决于 ABI。另一个区别是代码大小:<T: Borrow<Point>>
的每个唯一实例化表示函数的单态化,这会使二进制膨胀。第三个区别是降序:if Point
有析构函数,一个接受 T: Borrow<Point>
的函数将调用 Point::drop
在内部,而接受 &Point
的函数将对象留在原地供调用者处理。这是好是坏取决于上下文;但是,对于性能而言,它通常无关紧要(如果您假设 Point
无论如何最终都会被删除)。
一个接受 T: Borrow<Point>
的函数表明它正在用 T
做一些事情在内部,只有 &Point
可能是次优的。 Drop order 可能是这样做的最佳原因(我写了更多关于这个 in this answer 的文章,尽管我用作示例的 puts
函数并不是特别强大的函数)。
在manhattan
的情况下降序无关紧要,因为 Point
是 Copy
(简单复制的类型可能没有滴胶)。所以接受 Point
没有性能优势以及 &Point
(虽然单个函数不太可能以某种方式产生太大差异,但如果泛型被普遍使用,代码大小的成本很可能是一个缺点)。
避免不必要地使用泛型还有一个原因:它们会干扰类型推断,并且会降低编译器的错误消息和建议的质量。例如,假设 Point
仅实现 Clone
(不是 Copy
)并且你写了 manhattan(p, q)
然后使用 p
稍后在同一函数中再次使用。编译器会警告你 p
移入函数后使用,建议添加.clone()
.其实更好的办法是借p
,如果 manhattan
接受引用编译器将强制您这样做。
事实Point
很小(因此将其用作函数参数的开销可能很小)和 Copy
(所以不用担心滴胶)提出另一个问题:应该manhattan
只需接受 Point
并且根本不使用引用?这是一个基于意见的问题,实际上归结为哪个更适合您的心理模型。要么接受 &Point
,并使用 &
当调用者拥有自有值时,或接受 Point
,并使用 *
当来电者有引用时 - 没有硬性规定。Borrow
的正确用法是什么? , 然后?
上面的论点强烈依赖于引用很容易在任何地方使用的事实,因此您也可以在调用者中具体地将它们作为抽象地在泛型函数中。有一次情况并非如此,即借用或拥有的类型没有直接传递给函数,而是包装在另一个通用数据结构中。考虑对 Point
的切片进行排序- 类似事物与 (0, 0) 的距离:
fn sort_by_radius<T: Borrow<Point>>(points: &mut [T]) {
points.sort_by_key(|p| {
let Point { x, y } = p.borrow();
x * x + y * y
});
}
在这种情况下,绝对不是带有
&mut [Point]
的调用者的情况。可以简单地借用它来获得
&mut [&Point]
.然而我们想要
sort_by_radius
能够接受两种切片(无需编写两个函数)所以
Borrow<Point>
来救援。
sort_by_radius
的区别和您的版本
manhattan
是
T
不是直接传递给要立即借用的函数,而是
sort_by_radius
类型的一部分需要像对待
Point
为了执行最终与借用无关的任务(对切片进行排序)。
关于rust - 接受 `impl Borrow<T>` 的参数来抽象 T 的引用和值是惯用的 rust 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69307184/
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!