股票场内基金交易,没时间盯盘?

   
使用优财助手电脑客户端记录下您的股票买入卖出数据,能帮您时刻盯盘,会根据您记录的未售出买入价计算上涨或下跌幅度,及时弹框通知您。想知道如何使用?快点击左方视频观看了解吧~~下载地址:http://youcaizhushou.com

作者:Armin Ronacher 写于 2016/7/10

几个月前我决定写一个 Sentry 命令行客户端,为了解决手动调用的 Sentry API 的一些常见的任务(比如 dsym 或 sourcemap 管理起来很乏味)。在合适的可供选择的语言中,我选择了 Rust。这么选择的原因是,我希望人们能够下载一个单一的可执行文件,在静态状态下就可以链接一切。语言的可选项有 C,C++, Go 和 Rust,但是不可否认的是我太喜欢 Rust 了以至于对我来说这是一个极佳的选择。话说回来,Rust 是一个很强大的生态系统可以使我想要达成的目标变得更加容易。我从中得到的经验如下:

为 HTTP 选择合适的库

为了建立一个 HTTP 请求你要先选择一个库。特别推荐尝试两个 Rust 的库:hyperrust-curl。这两个我都试了,包括之前的一些版本。最终我选择了 rust-curl。这么做的原因有两个,首先 curl(虽然运行处理任务时有点古怪)非常强大并且和 SSL 库有非常好的集成,这意味着当我编译可执行文件后马上可以得到本机 TLS 支持。rust-curl(虽然不是一个纯粹的 rust 库)在 Windows,macOS 和 Linux 上编译运行都非常好。其次是 Hyper 目前正在经历一个重大的转变,准备进行结构化并且会有一些变化。我不想在这方面去赌太多,而且当我运行它时也没有代理服务器支持,這显得不够好。 JSON 解析与序列化方面我使用 serde。我觉得 serde 最终将是一个可以使一切序列化的库,虽然现在还不是。这取决于编译器插件,并且这里有两种方式来运行:一种是使用测试版 Rust(我采用的方法)。另一种是使用 Rust 支持的构建脚本,这类似于你使用 Go 所发生的那样,一些代码运行生成构建的一部分。它的确可以运行,但是比起用 serde 加测试版 Rust 来,会显得不那么好。

API 设计

接下来一个问题是对于一个 Rust HTTP 库来说,什么样的才是一个好的 API 设计。我为此挣扎困扰了很久,颇有反复,最终觉得的一个很好的模式是一个多种类型的集合:

  • Api:我有一个用于内部调用 api 的基本客户端对象,用来管理 curl 处理(目前只能缓存一个)并可以用方便的做法去执行某些特定类型的 HTTP 请求。最重要的是它可以提供高水准的方法来发送正确的 HTTP 请求并处理响应。
  • ApiRequest:基本上这是你的请求对象。它主要是一个用于请求的生成器,拥有方法来发送请求并得到一个响应对象。
  • ApiResponse:包含了从 HTTP 请求得到的响应。同时也提供了各种各样的工具来帮忙将响应转换成别的东西。
  • ApiResult<T>:这是一个大多数方法返回的结果对象。转换发生的错误是一种特殊的 API 错误,调用所有的 APIs 都可能发生。这意味着它可以容纳 curl 错误,格式错误,JSON 错误,IO 错误等等。

为了使你明白这是怎么回事,我还想展示给你一个高水准的可以使用大部分 API 的方法:

(注意到没我使用了新的问号语法?替代了更熟悉的 try!宏在这里)

所以这里发生了什么?

  1. 这是一个 Api 结构的方法。我们使用 get() 速记方法来进行 HTTP GET 请求,它接受一个 进行请求的 URL 参数。我们采用标准的字符串格式来在此创建 URL 路径。
  2. PathArg 是一个简单的包装器,可以自定义格式。不仅仅格式化一个值的属性,同时还对该值完全编码。
  3. get 方法的返回值是一个 ApiResult,它提供了一个方便的 convert() 方法可以同时做错误处理与反序列化。

JSON 处理在此是如何发生的?答案是 convert() 可以做到。因为 Vec 有自动反序列化器的实现。

错误处理

大部分的复杂性都隐藏在多层次的错误处理中。我花了很长时间思考这个设计,这就是为什么我终于发现了一个真的很喜欢的设计后特别开心。关于 HTTP 请求的错误处理的原因非常棘手,是因为你既想拥有应对特定错误情况的灵活性,又可以自动处理所有那些你不感兴趣的。 最终设计方案是我设计出了一个 ApiError 类型。库里面可能遇到的所有内部错误(curl 错误等等)会自动转换成一个 ApiError。如果你发送一个请求的返回值会是这样 Result。但是这里的问题在于,这个层面上没有 HTTP 错误(除了连接错误)实际上存储为 ApiError。反而一个失败的响应(例如因为 404 错误)会被存储为实际的响应对象。
在响应对象方面,你可以用这些方法来检查响应状态:

然而欣慰的是大部分时间你都没必要做这些事情。响应方法还提供了一种使不成功的响应转换为这样的错误:

这种方法耗费响应并根据响应条件来返回不同的结果。如果一切顺利的话响应的结果是不变的,然而只要产生了错误,我们可以先尝试用 ErrorInfo(这是我们的 API 返回的 JSON 响应) 反序列化主体,或者返回一个通用的错误信息与状态码。

什么是反序列化?它只是调用 serde 来反序列化:

你在这还可以看到的一件事是程序主体完全被缓存在内存当中。刚开始我很难抉择,但是这种情况实际上使 API 大幅度变得更好。因为使得你更好地只用去思考响应,排除了程序主体关于内存缓冲的一切使情况变得艰难的问题。在我们无法处理这个限制的情况下,我有额外的方法来传输输入数据。
在反序列化中我们匹配主体。主体是一个 Option ,我们可以转换成一个 &[u8] 来满足 Read 界面从而可以使用反序列化。
上述关于 to_result 方法的优点是运行得很好。通常情况下,一切顺利的话它将转换相关处理项为结果,并反序列化该响应。这就是我们为什么有这个 convert 方法:

复杂的使用样例

这有一些很好的使用样例。比如这是我们如何从 GitHub API 检查更新:

在这里我们默默忽略 404 错误,否则的话我们要解析响应 GitHubRelease 之类的结构并查看所有有价值的东西。调用 to_result 并没有成功,但是他可以自动处理所有其他响应的错误。

为了明白如 GitHubRelease 之类结构如何定义,这些是必须的:

管理 Curl 的处理方式

还有一件事就是我如何管理 curl 来处理事务是不可见的。curl 是一个 c 库并且在底层与 Rest 绑定。虽然它很好的定义类型并且不允许不安全代码使用,但是仍然感觉就是一个 c 库。特别是当有一个 curl “容易”处理的对象你应该挂起在请求与保持信号之间的时候。本博客的读者都知道,我非常讨厌几点比如不必要的保持状态的 APIs。所以我尽可能使之无状态。

“正确”处理是有一个“简单”处理池。然而我从不会同时有多个未完成的请求,所以不同于处理复杂的事物,我在 RefCell 中采用“简单”处理。 RefCell 是智能指针,能够移动 rust 通常在编译时运行时需要的借用语义。这是它大致看上去的情况:

如果你调用请求两次,你会得到一个运行时的应急警告,即使最后的结果仍然是对的,这对于我做的来说算的上比较好了。ApiRequest 对象本身实现了一个构建模式可以让你修改链接的对象调用。这就是当用于一个更复杂的情况下大致看起来的情形:

从中可学到的

至今为止我的用 Rust 处理事情的关键点如下:

  • Rust 绝对是用于构建命令行实用工具的一个极佳选择,它的生态系统一天天变得更加强大,并且已经有很多处理日常任务的实用工具箱。
  • 跨平台支持是极为出色的。在 Windows 上建立运行比起你通常使用的其他语言(包括 Python)不要太简单。
  • serde 是一个极好的库。很遗憾在正式版本的 rust 运行得不是很好,希望尽快能够改进。
  • rust 中的结果对象是没问题的,但是有时候不立即将数据转换成结果对象是有意义的。我最初马上将失败响应转换成错误,但是这肯定会极大地损害 APIs 的便利性。
  • 不要害怕使用 c 库比如 curl 而不是 Rust 原生程序。事实证明,Rust 的建立支持是非常杰出的,使得安装 rust-curl 库非常简单。它甚至还可以在 Windows 上编译 curl 本身。

如果你想看代码,客户端的整个版本库都可以在网上找到:getsentry/sentry-cli

   

想获得去掉 5 元限制的证券账户吗?

证券交易股票基金的佣金,不足 5 元会按照 5 元收取。比如交易 1000 元的股票,按照普遍的证券佣金手续费率万 2.5,其交易佣金为 0.25 元,小于 5 元,实际会收取佣金 5 元,买卖两次需要支付 10 元佣金成本,1% 的利润就这样没了。

如果您想去掉最低交易佣金 5 元限制,使用微信扫描左边小程序二维码,访问微信小程序「优财助手」,点击底部菜单「福利」,阅读文章「通过优财开证券账户无最低交易佣金 5 元限制」,按照文章步骤操作即可获得免 5 元证券账户,股票基金交易手续费率万 2.5。

请注意,一定要按照文章描述严格操作,如错误开户是无法获得免 5 元证券账户的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注