从 React 的视角谈谈 Rust 和 GTK

最近我尝试了多种框架,想要制作出既易用又容易安装的应用程序,但是都以失败告终;最后我决定转向 Rust 和 GTK,开始拥抱原生软件开发。

虽说以前我也短暂尝试过 GTK,但它对我来说还是很陌生的。在此之前,我在用户界面上的大部分经验都来自于 React 应用程序的构建。从 React 到 GTK 的过渡带来了一些挑战,其中多数是小部件原理上的差异造成的。用 Rust 写 GTK 是尤其困难的事情,因为 Rust 强制执行一些额外的规则来防止内存管理错误,并避免在线程上下文中执行不安全的操作。

在本文中,我将主要讨论如何将 React 的理念应用到 GTK 中,并重点介绍一些使 GTK 符合 Rust 规则所必需的技巧。Rust 制订了一些不好对付的强制规则,这些规则对于大多数开发人员来说都是陌生的;规则主要涉及值的共享方式,但在可变性方面也有严格的限制。我将在本文中遇到这些场景时指出它们。

本文中的所有示例均来自 FitnessTrax( https://github.com/luminescent-dreams/fitnesstrax/ ),这是一款遵循隐私优先原则的健身追踪应用程序。用户可以在他们的 PC 上的一处存储空间内收集健身和生物识别数据,而不必依赖那些可能无法持续保护用户数据的公司。

关于这款应用程序的外观我要说句抱歉,因为 0.4 版( https://savanni.luminescent-dreams.com/2020/01/03/weekly-ramblings/ )发布的时候,我还没去花时间了解 GTK 是如何处理样式的。我保证会尽快改进用户界面。

框架哲学上的一些差异

Conrod( https://github.com/PistonDevelopers/conrod )是针对 Rust 的一个图形工具包,它试着将函数式响应编程( https://en.wikipedia.org/wiki/Functional_reactive_programming )技术应用到了图形编程上;它的开发者它描述了两种有着明显区别的图形组件管理模式( https://docs.rs/conrod/0.61.1/conrod/guide/chapter_1/index.html#immediate-mode )。在大多数原生图形编程采用的通用模式,亦即“保留模式(retained mode)”下,开发人员将创建一个个屏幕组件,然后在它们的整个生命周期内一次次更新。在“立即模式(immediate mode)”下,组件将具有一个绘制(draw)方法,其中组件会立即实例化自身的所有子级。然后,框架将对比这棵树与上一棵树,来判断该如何更新屏幕。

React 完全运行在即时模式下,而 GTK 完全运行在保留模式下。在 Web 开发行业中流行的数据可视化库 D3( https://d3js.org/ )也可以运行在保留模式下。2018 年,我写了一篇关于 React 和 D3 之间对接的文章( https://www.cloudcity.io/blog/2018/08/07/breaking-d3s-deathgrip-on-the-dom-bringing-old-code-back-to-life-in-a-react-era/ )。

与 Redux 或 Apollo-GraphQL( https://www.apollographql.com/ )搭配的 React 实现了函数式响应编程(FRP)的一些理念,让它可以自动处理传播到组件的数据更改。我入门 FRP 时看的是 Elise Huard 写的一本书“Haskell 中的游戏编程”( https://leanpub.com/gameinhaskell )。时至今日这本书可能已经过时了,但在 Haskell 中特定的某个 FRP 库的背景下,它确实很好地介绍了这种理念。不幸的是,FRP 尚未在 React 之外得到广泛采用。虽说至少有一个可用于 Rust 的 FRP 库,但在撰写本文时,对于我来说采用它还为时过早。因此,凭借一些创造力和我在 React 领域的经验,我设计了一些类似于 FRP 范式的机制。

一些术语的注释:

  • 小部件(widget)是一个 GTK 对象,代表屏幕上的某些内容。它可以是一个窗口、按钮、标签或一个布局容器。GTK 小部件只能将其他 GTK 小部件作为自身的子级。
  • 组件是屏幕上一个部分的任意逻辑抽象。在简单的情况下,它会是一个从某个函数返回的 GTK 小部件。在更复杂的情况下,它可能是包含一个或多个小部件的结构。组件不一定必须传递给 GTK 函数。结构组件始终提供一个’widget’字段,其代表这个组件的根小部件。

不可变值的显示

所有组件中最简单的,就像 React 组件一样是一小组小部件,这些小部件创建后就永远不会更新。这可以简单地实现为返回一个 GTK 小部件的函数。


查看更多

想要查看更多内容点击文末了解更多查看


分享到:


相關文章: