贝壳 借贷计算器

This post discusses how ad-hoc structs designed to be implementation details can be used to reintroduce aliasing to rust and cut down on the number of fights with the borrow checker.

这篇文章讨论了如何将被设计为实现细节的临时结构用于重新引入别名以防锈并减少借阅检查器的打架次数。

This was going to be the post with the most clickbaitiest title I was ever going to write. I couldn’t quite bring myself to do it, but here is the title I was going to use: “How this one simple trick can be used to end most fights with the borrow checker.” Marvelously bad.

这将是我有史以来点击次数最多的标题。 我不能完全自己做,但是这里是我要使用的标题:“如何使用这个简单的技巧来结束大多数借用检查器的操作。” 太糟糕了。

So, here is that one simple trick: When fighting with the borrow checker, consider moving your variables and your functions into a struct in place of using references.

因此,这是一个简单的技巧:与借位检查器配合使用时,请考虑将变量和函数移到结构中,以代替使用引用。

Admittedly, this might need a bit more elaboration: When I started coding in rust, coming from other languages like javascript and c++, I noticed that a few of the patterns I was using consistently led to fights with the borrow checker. In fact, most of these patterns where intentionally prohibited in rust; usually with good reason which makes the entire situation just so much more infuriating. After going through this process a couple of times, I found that often the solution I would come up with involved refactoring my code by wrapping the offending variables and functions in a struct.

诚然,这可能需要更多的阐述:当我开始使用来自javascript和c ++等其他语言的rust进行编码时,我注意到我一直使用的一些模式导致与借用检查器发生冲突。 实际上,大多数这些模式都是故意禁止生锈的。 通常是有充分理由的,这使整个情况更加令人生气。 经过几次此过程后,我发现通常想出的解决方案是通过将有问题的变量和函数包装在结构中来重构代码。

In this blog post we will look at a couple examples for these kinds of situations and finally discuss the underlying reason why creating a new struct is a solution that works in these cases.

在此博客文章中,我们将看一些针对此类情况的示例,并最终讨论创建新结构是在这些情况下有效的解决方案的根本原因。

全局变量 (Global variables)

Global variables are a common occurrence in most languages, but in rust globals (or statics as they are called in rust) are discouraged. You can only initialize them with constant expressions which rules all constructors that need some sort of memory allocation or rely on dynamic data like the contents of an external file. This rule is the reason why the following example will fail at compile time:

全局变量在大多数语言中很常见,但在rust全局变量(或称为rust的静态变量)中不建议使用。 您只能使用常量表达式对它们进行初始化,该常量表达式将控制所有需要某种内存分配或依赖于动态数据(例如外部文件的内容)的构造函数。 此规则是以下示例在编译时失败的原因:

We can solve this problem by using Vec::new(), which creates an empty vector and is a constant function. Any memory will be allocated later once we manually add our data:

我们可以使用Vec :: new()解决这个问题,它创建一个空向量并且是一个常数函数。 一旦我们手动添加数据,所有内存都将在以后分配:

Great, this works! Unfortunately we had to use unsafe blocks to add our data, because as it turns our rust prohibits accessing mutable global variables in safe code for thread safety reasons: Without this restrictions two threads may access the object at the same time, causing a race condition.

太好了,这有效! 不幸的是,我们不得不使用不安全的块来添加我们的数据,因为出于线程安全的考虑,由于生锈,它禁止访问安全代码中的可变全局变量:如果没有此限制,则两个线程可能会同时访问该对象,从而导致竞争。

There is a number of ways to solve this problem; one of the easiest: do not use a global variable at all. By moving our global variables as well as the functions using them into a struct, we can not only sidesteps the thread safety/static mutable issue, but also start using a non constant initializer again.

有很多方法可以解决此问题。 最简单的方法之一:根本不使用全局变量。 通过将全局变量以及使用它们的函数移入结构,我们不仅可以避开线程安全性/静态可变问题,而且可以再次开始使用非常量初始化器。

混叠 (Aliasing)

The rust borrow checker bans mutable variable aliasing. This is a good thing, but for me it was a hard pill to swallow as aliasing is a feature I had been using quite a lot just to give descriptive names. Usually these aliases either take the form of a reference, renaming variable nested deeply in one of my objects. Other times my aliases take the form of a closure, giving a descriptive name to a simple code snippet as well as making that snipped reusable. Used carefully, aliasing can help structure long, complex pieces of code and aide in communicating your intentions to other developers well. Given the choice between an alias and a line of documentation, I will often choose the alias.

锈借阅检查器禁止可变变量别名。 这是一件好事,但是对我而言,这是一个难以下咽的药,因为别名是我经常使用的功能,只是为了提供描述性的名称。 通常,这些别名采用引用的形式,重命名嵌套在我的对象之一中的变量。 其他时候,我的别名采用闭包的形式,为简单的代码段指定一个描述性名称,并使其可重用。 谨慎使用别名可以帮助构建冗长而复杂的代码,并有助于将您的意图很好地传达给其他开发人员。 给定别名和一系列文档之间的选择,我经常会选择别名。

The following — broken — example uses a few aliases: avg is an alias because we need to use it multiple times and because it divides by zero for empty sample vectors. mag is an alias and not a free function because it's behaviour is not well defined for negative values. Finally, new_is_outlier is just there to give a relatively opaque formula a clear name.

以下是一个破碎的示例,它使用了一些别名: avg是一个别名,因为我们需要多次使用它,并且对于空的样本矢量,它除以零。 mag是别名而不是自由函数,因为它的行为没有很好地定义为负值。 最后,只需提供new_is_outlier即可为相对不透明的公式提供清晰的名称。

Using aliases just made a bunch of relatively random code much easier to read and understand — just imagine how long it would take to understand that this code is doing outlier rejection if all you had was some weird, code containing a bit of math. Unfortunately, this code is also broken: our closures need to borrow a reference to the arguments and this stops us actually mutating the arguments. Luckily, by moving our code into a struct, we can keep the nice names and keep the reusability; our code becomes just a little harder to read a little more verbose.

使用别名使一堆相对随机的代码更易于阅读和理解-想象一下,如果您所拥有的只是一些怪异的代码(其中包含一些数学知识),那么理解该代码要进行离群值拒绝将花费多长时间。 不幸的是,这段代码也被破坏了:我们的闭包需要借用对参数的引用,这实际上阻止了我们对参数进行修改。 幸运的是,通过将代码移到结构中,我们可以保留漂亮的名称并保持可重用性。 我们的代码变得更难阅读一些冗长。

Of course we could also solve this by promoting our aliases to become proper, well defined functions; avg could be a generic average function and the same goes for mag which could be turned into a factor_magnitude function. Both changes would introduce a lot of extra complexity; we would have to decide what avg should do if the input collection is empty, document it properly, test it properly, adapt it to work for any Iterator, use a longer name and explicitly pass in the iterator from the outside. Similar caveats apply for mag and new_is_outlier.

当然,我们也可以通过将别名提升为适当的,定义明确的功能来解决此问题; avg可以是通用平均函数,而mag也可以转换为factor_magnitude函数。 两种更改都会带来很多额外的复杂性。 我们必须决定如果输入集合为空,平均记录,正确测试,使其适应于任何迭代器,使用更长的名称并从外部显式传入迭代器,则应如何处理avg。 类似的警告适用于magnew_is_outlier

No, if we really just need those functions for add_sample and nowhere else, we might just treat them as implementation details and skip that extra maintenance required to make them function in any and all contexts.

不,如果我们真的只需要add_sample那些功能,而没有其他地方,则可以将它们视为实现细节,并跳过使它们在任何和所有上下文中起作用所需的额外维护。

参观者 (Visitors)

Finally I would like to look at an example quite similar to to the aliasing ones: Using closures as event handlers. In the following example, a function produces two sorts of events, one for warnings one for errors. Both are handled by passing a closure to the function.

最后,我想看一个非常类似于别名的示例:使用闭包作为事件处理程序。 在下面的示例中,一个函数产生两种事件,一种用于警告,另一种用于错误。 两者都通过向函数传递闭包来处理。

Now we solve that the same way we solved lifetime problems in the previous examples: By moving our closures into a struct, as we did before. I will leave that as an exercise to the reader, because this time we are more interested in the sort of structure we end up with after the move.

现在,我们以与解决前面示例中的生命周期问题相同的方式来解决问题:像以前一样,通过将闭包移动到结构中。 我将其留给读者练习,因为这一次我们对搬迁后的最终结构更加感兴趣。

What we end up with is called a visitor; a method of processing events or data in arbitrary order by assigning each event a method. This sort of construction is used in a lot of places; a particularly common application for visitors involves walking any sorts of tree-like structure. For instance, we could use a visitor to walk our file system tree; you could just declare one method for handling files, one for handling directories and one for symbolic links.

我们最终将其称为访客。 通过为每个事件分配一个方法以任意顺序处理事件或数据的方法。 这种结构在很多地方都使用过。 对于游客来说,一种特别常见的应用涉及步行各种树状结构。 例如,我们可以使用一个访问者来遍历我们的文件系统树; 您可以只声明一种用于处理文件的方法,一种用于处理目录的方法以及一种用于符号链接的方法。

Here is another example, using a visitor to serialize data as JSON:

这是另一个示例,使用访问者将数据序列化为JSON:

Note how we first define a trait with our events ( start_obj, end_obj, number, string, ...), then create separate sources ( example_json) and finally the sinks ( JsonGenerator, our visitor); this sort of decoupling using traits makes visitors the lowest common denominator for a lot of possible use cases. The decoder could be hard coded, read from an efficient-to-decode binary stream or be a full blown json decoder dynamically selecting with method/event to invoke. The same holds true for the visitor itself: this could just search for some specific value, generate json or even transform the events on the fly and forward them to another visitor. Applications using this pattern can be extremely efficient, relying on lot's of inlining or rely on much less efficient dynamic dispatch. They can be asynchronous or process a stream of events already stored in memory all at once.

注意我们如何首先使用事件( start_objend_objnumberstring ,...)定义特征,然后创建单独的源( example_json ),最后创建接收器( JsonGenerator ,我们的访问者); 这种使用特征的解耦使访问者在许多可能的用例中成为最低的公分母。 解码器可以是硬编码的,可以从有效解码的二进制流中读取,也可以是完整的json解码器,可以动态选择要调用的方法/事件。 访客本身也是如此:这可以仅搜索某些特定值,生成json甚至即时转换事件并将其转发给另一个访客。 使用这种模式的应用程序可能非常高效,它依赖大量内联或依赖效率低得多的动态调度。 它们可以是异步的,也可以一次处理已经存储在内存中的事件流。

This level of flexibility makes them especially suitable for data conversion frameworks. At the core of these, some sort of visitor pattern can usually be found; create decoders and encoders for a couple of formats and you have yourself a converter between any two of these formats. Finally, higher level, more convenient interfaces, like DOM style interfaces can be generated/exported using their own pair of encode/decode visitors.

这种灵活性使它们特别适合于数据转换框架。 在这些核心中,通常可以找到某种访客模式。 为两种格式创建解码器和编码器,您就可以在这两种格式之间进行转换。 最后,可以使用它们自己的一对编码/解码访问者来生成/导出更高级别,更方便的接口,例如DOM样式接口。

Check out Serde’s Encoder Visitor Trait for for just one of the many examples.

查看Serde的Encoder Visitor Trait只是众多示例之一。

结论 (Conclusion)

In this post we looked at three examples of borrow checker complaints that can be solved by moving the offending functions, closures and variables into a struct. In each of these cases this worked because by using structs we implicitly started using a form of control inversion. Instead of storing a reference to whatever variable we needed inside our function, closure or our alias, we would hand over the variable from outside every time. Embedding our variables inside a struct just allowed us to keep things convenient and easy to read despite implementing inversion of control.

在这篇文章中,我们看了三个借阅检查器投诉的示例,可以通过将有问题的函数,闭包和变量移入结构来解决。 在每种情况下,这种方法都是有效的,因为通过使用结构,我们隐式开始使用一种控制反转形式。 无需在函数,闭包或别名中存储对所需变量的引用,而是每次都从外部移交变量。 尽管实现了控制反转,但将变量嵌入结构体中仍使我们能够使事情保持方便且易于阅读。

There is another commonality among our examples: All three are ad-hoc solutions you might often find in other languages, especially javascript; these sorts of patterns are used whenever we just need to reuse some snippet of code or assign an alternate name to a variable. I struggle even with the term ad-hoc solution (or worse, hack, quick fix) because having these reusable implementation details is often the best possible solution. Introducing a brand new public interface adds maintenance burden and prevents future refactoring. Expanding your public facing interface — your API — is a step that should not be taken lightly; premature abstraction is the bane of many software projects.

我们的示例之间还有另一个共同点:这三个都是您可能经常在其他语言(尤其是javascript)中找到的即席解决方案; 每当我们只需要重用一些代码片段或为变量分配替代名称时,便会使用这种类型的模式。 即使使用术语临时解决方案(或更糟糕的是,hack,快速修复),我也感到吃力,因为拥有这些可重用的实现细节通常是最好的解决方案。 引入全新的公共界面会增加维护负担,并阻止将来的重构。 扩展面向公众的接口(即API)是不应该掉以轻心的一步。 过早的抽象是许多软件项目的祸根。

Object Oriented Development has taught us that having ad-hoc classes is not OK. Classes should be these pristine things with a nice API. Definitely no public fields. I urge you to let go of that notion; API design is an art in of it self; an excellent API is much more — and much less — than a list of structs contained in library.

面向对象开发告诉我们,临时类是不行的。 类应该是具有原始API的这些原始的东西。 绝对没有公共领域。 我敦促你放开这个观念。 API设计本身就是一门艺术。 一个优秀的API比库中包含的结构列表要多得多,也要少得多。

In conclusion, I would say, that one important step in learning to work with the borrow checker instead of against it is this: Learn not to shy away from using structs as implementation details when implementing a functions.

总之,我要说的是,学习而不是反对使用借贷检查器的一个重要步骤是:学会在实现功能时不要回避使用结构作为实现细节。

翻译自: https://medium.com/adobetech/how-i-learned-to-stop-fighting-the-borrow-checker-and-learned-to-love-dirty-structs-b6c5fe91b1dd

贝壳 借贷计算器

http://www.taodudu.cc/news/show-3246154.html

相关文章:

  • SitePoint Podcast#51:真正的Web设计师获得它
  • 响应式web设计_将响应式Web设计超越视觉
  • 软件构造 2019
  • ui和ux的区别_UX和UI之间的区别
  • 【论文翻译】卷积神经网络研究综述
  • rsa私钥和公钥_如何创建RSA公钥和私钥?
  • 首款 MetaFi 游戏来袭,Ultiverse 是 Ready Player One 的复制吗?
  • 41页数字政府整体规划方案 —数化万物赋能
  • 【Leetcode之算法思想】
  • 物联网IoT:开源代码基于CNN的红外图像人检测夜间入侵预警系统
  • 高性能计算系统——大数据与快速数据分析对高性能分析的需求
  • RuntimeError: cuda runtime error (11) : invalid argument at /pytorch/aten/src/THC/THCGeneral.cpp
  • colab中遇到“THC/THC.h: No such file or directory”的解决办法
  • 【Bug解决】invalid argument at /pytorch/aten/src /THC/THCGeneral.cpp:405
  • PyTorch报错:RuntimeError: CUDA error: device-side assert triggered at /pytorch/aten/src/THC/generic
  • python出现THCudaCheck FAIL file=/pytorch/aten/src/THC/ThCGeneral.cpp line=405 error=11 : 情况
  • PyTorch 错误 RuntimeError: invalid argument 5: k not in range for dimension at /pytorch/aten/src/THC/g
  • device-side assert triggered at /pytorch/aten/src/THC/THCReduceAll.cuh:327
  • 关于THC/THC.h: No such file or directory解决办法
  • pytorch 报错“THCudaCheck FAIL file=/pytorch/aten/src/THC/THCGeneral.cpp line=663 error=11“解决方案
  • PointTransformer编译pointops_cuda报错fatal error: THC/THC.h: No such file or directory
  • Thc-ssl-dos
  • RuntimeError: cuda runtime error (30) : unknown error at /pytorch/aten/src/THC/THCGeneral.cpp:50
  • [debug]THCudaCheck FAIL file=/pytorch/aten/src/THC/THCGeneral.cpp line=405 error=11 : invalid argume
  • RuntimeError: cuda runtime error (3) : initialization error at /pytorch/aten/src/THC/THCGeneral.cpp:
  • SSL压力测试工具--thc-ssl-dos
  • THCudaCheck FAIL file=/opt/conda/conda-bld/python/pytorch/work/aten/src/THC/THCCachingHostAllocator.
  • pytorch在调用GPU的时候出现cuda runtime error (2) : out of memory at ..\aten\src\THC\THCGeneral.cpp:50
  • thc--hydra暴力破解
  • thc-ssl-dos攻击https站点

贝壳 借贷计算器_我如何学会停止与借贷检查器战斗并爱肮脏的结构相关推荐

  1. ui与前端的仇恨_我如何学会停止仇恨并开始喜欢Windows 8

    ui与前端的仇恨 Windows 8 has been with us for a good few months now. From consumer previews to the release ...

  2. 用yacc编写的算术运算计算器_详细的mac计算器操作技巧+快捷键分享

    我们的mac自带的计算器并不只可以应用于简单的计算,还有很多强大的实用功能你知道吗?今天小编就来带你解锁这些计算器的新功能.并有快捷键奉上~ 使用"计算器"执行基本计算.高级计算或 ...

  3. windows7系统损坏修复_修复损坏的系统文件,就用系统文件检查器SFC,简单高效...

    Windows 10上许多系统问题都是由损坏的系统文件引起的,那么如何使用SFC命令程序修复Windows 10上的系统文件呢? 有没有注意到,使用电脑时,经常会出现Windows无法正常工作或Win ...

  4. qtwebengineprocess已停止工作_windows资源管理器总是停止工作

    一. 在 Windows 中工作时,你可能会收到以下错误消息: Windows 资源管理器已停止工作. Windows 正在重启 此外,你可能会在错误消息出现前后注意到屏幕闪烁. 二. 当出现wind ...

  5. win7或win2008系统中,出现【已停止工作,联机检查解决方案并关闭该程序,关闭程序】解决方法!

    win7或win2008系统中,出现[已停止工作,联机检查解决方案并关闭该程序,关闭程序]解决方法! 经过摸索,点击[控制面板]-[操作中心]-[更改操作中心设置]-[问题报告设置]-[从不检查解决方 ...

  6. 借贷宝有多少人看得懂?借贷宝系统崩溃分析

    动动手指,20元人民币立即到手:http://www.cnblogs.com/mfryf/p/4754384.html 借贷宝官方20元现金领取地址:http://qiangqian.jiedaiba ...

  7. 60进制时间计算器_不止加减乘除,Windows 自带计算器还有这些隐藏技巧

    2019 年 3 月 7 日,微软选择将计算器功能放到 GitHub 上开源,以提升计算器的用户体验.计算器跟随了 Windows 系统这么久,但你用过多少次呢?你知道目前 Windows 自带的计算 ...

  8. 五元一次方程组计算器_人教版初中数学七年级下册列一元一次不等式解实际问题公开课优质课课件教案视频...

    9.2 一元一次不等式的应用(1)教案设计 一.教学目标 1.知识与技能目标 :掌握用一元一次不等式解决实际问题的步骤,能够根据具体问题中的数量关系列出一元一次不等式组解决简单的实际问题,并能根据具体 ...

  9. 电脑计算器_手把手教你使用初级会计机考系统计算器!

    备考初级会计的你是否还执着于做纸质习题?还在一次次的手动计算?偷偷告诉大家,别人已经开始模拟机考答题啦!又有人问:"机考自带的计算器用不明白怎么办?",别急,小奥将在本文为大家介绍 ...

最新文章

  1. linux入门教程(二)
  2. Zookeeper配置文件中的配置项解释和Zookeeper的安装
  3. ML之Clustering之K-means:K-means算法简介、应用、经典案例之详细攻略
  4. iOS发展- 文件共享(使用iTunes导入文件, 并显示现有文件)
  5. Delphi 正则表达式语法(9): 临界匹配 - 也叫预搜索与反向预搜索
  6. 【CF1189D】Add on a Tree【结论】【构造】
  7. python 字符串大小写转换 其它不变_python字符串大小写如何转换
  8. 使用Apex进行混合精度训练
  9. BootLoader简介——linux内核的引导
  10. C语言实现简单学籍管理系统
  11. MarkDown、Vim双剑合璧
  12. PHP运算符 - 对象的方法或者属性, =数组的元素值
  13. vue中动态添加组件
  14. 架构之美第四章-架构与美
  15. 鹅厂开源框架tars之基础组件
  16. 小巧的menuetOS
  17. Amy-Tabb机器人世界手眼标定(1、环境搭配)
  18. 基于python的火车票售票系统/基于django火车票务网站/火车购票系统
  19. 文章采集软件怎么采集文章?
  20. Gitlab安装使用及汉化配置

热门文章

  1. 金山员工猝死:莫让青春负重前行
  2. 物联网毕设 -- 人脸打卡系统(WIFI+APP+OneNet)
  3. IP防尘防水等级测试标准
  4. 【翻译】Focal Loss for Dense Object Detection(RetinaNet)
  5. 为什么cpu制程工艺非要追求7nm、5nm甚至2nm
  6. String类的Intern()方法
  7. 百度地图大数据MapV的相关介绍
  8. vue解决闪现遇到的问题
  9. 对于load方法的理解
  10. 关于卡塔尔世界杯的活动介绍