Xilem:Rust中的UI架構

banq發表於2022-05-08

由於各種原因,Rust是一種用於構建使用者介面的吸引人的語言,特別是它承諾提供效能和安全。然而,找到一個好的架構是具有挑戰性的。在其他語言中執行良好的架構通常不能很好地適應Rust,主要是因為它們依賴於共享的可改變的狀態,而這並不是Rust的習慣。
由於這個原因,有時會有人斷言Rust不適合於UI。
我一直認為有可能找到一個非常適合在Rust中實現的UI架構,但我之前的嘗試(包括目前的Druid架構)都是有缺陷的。我研究了一系列其他的Rust UI專案,覺得這些專案也都沒有合適的架構。

這篇文章提出了一個新的架構,它是對現有工作和一些新想法的綜合。我們的目標包括用易於組合的元件來表達現代反應式、宣告式的UI,以及高效能的實現。對於那些熟悉SwiftUI、Flutter和React等先進工具包的人來說,用這種架構編寫的UI程式碼將顯得非常直觀,同時也是Rust的術語。

Xilem "這個名字來自於木質部,這是維管束植物(包括樹木)的一種運輸組織。這個詞在包括羅馬尼亞語和馬來語在內的幾種語言中都是用 "i "來拼寫的,它指的是xi-editor,這是探索Rust中UI的一個起點(現在被擱置了)。

像大多數現代UI架構一樣,Xilem是基於檢視樹的,它是對UI的簡單宣告性描述。對於增量更新,檢視樹的連續版本會被差異化,而結果會被應用到小部件樹上,這更像是一個傳統的保留模式的UI。Xilem的核心還包含一個增量計算引擎,具有精確的變化傳播,專門用於使用者介面。

Xilem最創新的方面是基於ID路徑的事件排程,在每個階段提供對應用狀態的可變訪問。一個獨特的功能是適應節點(Druid中透鏡概念的演變),它有助於元件的組成。透過將事件透過適應節點進行路由,子元件可以訪問與父元件不同的可變狀態參考。

對現有架構的快速瀏覽
這個架構的設計是為了解決現有技術水平的侷限性和問題,包括目前的Druid架構和其他嘗試。如果不瞭解這些架構,就很難理解其中的一些動機。也就是說,對反應式使用者介面架構的全面調查將是一項相當長的工作;本節只能觸及其中的重點。

現有的Druid架構有一些很好的功能,但我們一直看到人們在共同的主題上掙扎。

  • 建立靜態widget層次結構和動態更新它們之間有很大的區別。
  • 應用程式的資料必須有一個資料繫結,這意味著克隆和平等測試。內部可變性實際上是被禁止的。
  • 鏡頭lens機制是混亂的,實現複雜的繫結模式並不容易。
  • 我們從未想出如何以一種令人信服的方式整合非同步
  • 有一種環境機制,但它並不高效,而且不支援細粒度的變化傳播。

另一個常見的架構是即時模式GUI,包括相對純粹的形式和修改後的形式。它在Rust中很受歡迎,因為它不需要共享可變的狀態。它還得益於整體系統的簡單性。
然而,該模式在很多方面都過於簡化了,而且很難做到複雜的佈局和其他模式,而這些在保留的部件系統中則更容易。
還有許多與有時渲染陳舊狀態有關的紙上談兵。(我在 "crochet "架構實驗中用保留部件的後端模擬即時模式的API進行了實驗,結論是結果並不令人信服)。
流行的egui crate是即時模式的可靠實現,makepad也是基於它的,儘管它在一些重要方面有所不同。

Rust中一個特別常見的UI架構是The Elm Architecture,它也不需要共享可變的狀態。相反,為了支援來自UI的互動,手勢和其他相關的UI動作建立了訊息,然後被髮送到一個更新方法,該方法採取中央應用程式狀態。
Iced、relm和Vizia都使用這種架構的某種形式。一般來說,它工作得很好,但需要建立一個明確的訊息型別並對其進行排程,這很繁瑣,而且Elm架構並不像其他一些架構那樣支援乾淨的派生元件。Elm文件特別警告不要使用元件,說:"在Elm中積極嘗試製作元件是災難的根源"。

最後,有一些認真的嘗試將React模式移植到Rust中,其中我認為Dioxus最有希望。這些依賴於內部可變性和其他模式,我認為這些模式對Rust的適應性很差,但絕對代表了這裡提出的想法的一個可靠的替代方案。我想我們將不得不建立一些東西,看看它們的效果如何。

同步的樹
Xilem的架構是圍繞著生成樹和保持它們的同步而建立的。以這種方式,它是對我以前的博文中所描述的想法的完善,即建立一個統一的反應式使用者介面理論。

在每個 "週期 "中,應用程式產生一個檢視樹,並從該樹中獲得渲染。這個樹的壽命相當短;每次更新UI,都會產生一個新的樹。從這裡,一個部件樹被建立(或重建)。檢視樹只保留足夠長的時間來協助事件排程,然後與下一個版本進行比較,這時它就被放棄了。相比之下,部件樹在不同的週期內持續存在。除了這兩棵樹之外,還有一棵包含檢視狀態的樹,它也是跨週期儲存的。(檢視狀態的功能與React鉤子非常相似)。

在現有的UI架構中,檢視樹與SwiftUI的架構最為相似:
檢視樹中的節點是普通的值物件。它們也包含回撥,例如指定點選按鈕時要採取的行動。
和SwiftUI一樣,但對於動態語言中的UI來說,檢視樹是靜態型別的,但在嚴格的靜態型別過於嚴格的情況下,有一個型別化的逃生艙(Swift的AnyView)。

這些樹的Rust表達是View trait的例項,它有兩個相關的型別,一個是檢視狀態,一個是相關的部件。狀態和部件也是靜態型別的。這個設計在很大程度上依賴於Rust編譯器的型別推理機制。除了推斷檢視樹的型別外,它還使用關聯型別來推斷關聯狀態樹和部件樹的型別,這些型別在編譯時是已知的。在幾乎所有其他類似的系統中(SwiftUI是一個明顯的例外),這些都是在執行時透過相當數量的分配、下轉換和動態排程來確定的。

。。。
詳細點選標題

總結:
這裡的一個難點是,在為 Web 基礎設施構建的反應式架構上做了大量工作,並且很難將這些與為原生 UI 構建的東西進行比較。解決這個問題的一種方法是根據 Xilem 的想法構建一個原型響應式 Web 引擎。

相關文章