從 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 小部件的函數。


查看更多

想要查看更多內容點擊文末了解更多查看


分享到:


相關文章: