日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

编程界的“二向箔”——Dart元编程

發(fā)布時間:2024/8/23 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编程界的“二向箔”——Dart元编程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

閱讀過《三體》的同學肯定知道“降維打擊”,從更高維度看問題,直接將對手KO。今天我們閑聊一下編程界的“二向箔”——元編程。

1. 什么是元編程

我們聽過了太多太多的名詞,耳朵似乎都有點名詞麻痹癥了。比如,有些名詞為了裝x(比如筆者的文章標題...)或者其本身的意義難以定義,就會加上一些似乎閃爍著光芒的前綴——如meta。計算機軟件這行業(yè)就有meta data, meta model, meta programming。
今天我們裝x的主角就是meta programming——元編程。
其實網(wǎng)絡上也能搜出很多相關的文章,對于該詞的定義參考wikipedia的一句話:

Metaprogramming is a programming technique in which computer programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyze or transform other programs, and even modify itself while running. In some cases, this allows programmers to minimize the number of lines of code to express a solution, in turn reducing development time. It also allows programs greater flexibility to efficiently handle new situations without recompilation.

簡而言之,就是將程序作為數(shù)據(jù),可以用于操作程序或者自身,而實現(xiàn)某些能力,比如將運行時工作移到編譯時。
按照編譯器發(fā)展的進程,元編程可實現(xiàn)如代碼替換(通過宏實現(xiàn)),泛型編程(從宏演變而來,脫離類型,高度抽象邏輯,可減少代碼量),或者在更高級的語言中,運行時通過內(nèi)省/反射機制來操作代碼邏輯,或者隨著編譯過程的解耦和開放,可以實現(xiàn)在中間語言階段(AST,IL),操作語法樹和中間語言,實現(xiàn)更可擴展性的能力。

Dart做為一門現(xiàn)代高級語言,除了模板化能力,也能基于中間語言來操作代碼。本篇文章主要討論如何基于其中間語言(dill),通過AST樹的操作來進行元編程,并實現(xiàn)一些現(xiàn)有dart語法本身實現(xiàn)不了的能力。并且這種實現(xiàn)在編譯時,對于程序在運行時的性能幾乎沒有影響。

2. Dart中的元編程簡介

2.1 背景知識

我們知道,幾乎任何語言中,代碼在 "編譯"(解釋型語言在運行時也有編譯的過程) 的過程中,都會生成一種樹狀的中間狀態(tài),這就是 AST(抽象語法樹)。AST 描述了每個表達式/語句中的子語句的執(zhí)行順序和執(zhí)行邏輯,因而它可以被很方便地翻譯成目標代碼 。基于這種抽象,能合理的將編譯器拆分為三階段:FrontEnd,Optimizer, Backend,從而實現(xiàn)能兼容各種語法形式的語言,更易于遷移并兼容不同架構的cpu。見下圖:

?

這三個階段圍繞這IL(intermediate language)進行。IL語言隔離了語法(能輕易適配各種新的語種),平臺架構等的差異性。

?

2.2 Dart的編譯流程

Dart的設計也類似,其中間語言就是Dill。不同的是,這里的Dill不像java的IL或者DotNet的IL那樣開放出來可以直接編寫,而是通過程序的方式操作實現(xiàn)。

這種方式其實就是基于AST庫對Dill進行manipulation。

這個庫內(nèi)的組件包含了所有AST樹涉及到的節(jié)點的定義和訪問,將類型,函數(shù),語句,聲明,表達式等編程基本概念抽象成了對象。基于這些對象我們可以遍歷整個AST樹, 或者生成新的類型和函數(shù),插入代碼語句,實現(xiàn)新的邏輯。

2.3 幾個栗子

入門其實很簡單,看一下例子代碼就可以啦。

2.3.1. 比如以下語句定義了一個新的Map變量,并且調(diào)用了它的構造函數(shù):

//組裝參數(shù) Arguments mapFromArgs = Arguments.empty(); mapFromArgs.positional.add(MapLiteral([], keyType:keyInterType)); //調(diào)用from構造函數(shù) StaticInvocation mapConstructor = StaticInvocation(MapFromFactoryProc, mapFromArgs); //聲明一個名字為jsonMap的Map類型變量 VariableDeclaration mapInstDecl = VariableDeclaration("jsonMap", type:mapInterType); //相當于var jsonMap = new Map(); VariableSet set_mymap = VariableSet(mapInstDecl, mapConstructor);

2.3.2. 創(chuàng)建函數(shù)體

函數(shù)體其實就是Block。

Block bodyStatements = Block(List<Statement>()); bodyStatements.addStatement(mapInstDecl); bodyStatements.addStatement(ExpressionStatement(inst));

2.3.3 創(chuàng)建函數(shù)

這個例子是參考某個函數(shù)的聲明形式來創(chuàng)建新函數(shù),篇幅所限,一些參數(shù)從略。

static Procedure createProcedure(Procedure referProcedure ,Statement bodyStatements, DartType returnType) {FunctionNode functionNode = new FunctionNode(bodyStatements,//...參數(shù)從略);Procedure procedure = new Procedure(Name(referProcedure.canonicalName.name, referProcedure.name.library),ProcedureKind.Method, functionNode,//...參數(shù)從略);return procedure;} //調(diào)用函數(shù)創(chuàng)建,并添加到類定義中 Procedure overridedToJsonFunc = createProcedure(jsonTypes.StaticBaseToJsonProc, bodyStatements, InterfaceType(mapClass)); youClazz.addMember(overridedToJsonFunc);

2.3.4 其他

基于AST還可以創(chuàng)建復雜的表達式和語句,如ForInStatement(for...in循環(huán))等,語句和表達式還可以通過ExpressionStatement和BlockExpression互相轉(zhuǎn)化。更多的技巧可參考AST的定義。

2.4 如何調(diào)試

編輯好的Dill似乎是個黑盒,除了看日志或者看異常堆棧,并不能進行單步調(diào)試,給開發(fā)帶來了一些困難。但Dart提供了已將將kernel dill轉(zhuǎn)成可閱讀的文本的工具,方便調(diào)試:

$DartHome/dart ../../pkg/vm/bin/dump_kernel.dart /your/dill/file/path /output/dill/text/file.text

打開的text文件是類似于這樣的:

static method __from_Json1(core::Map<dynamic, dynamic> m) → aop2::UserDataT {aop2::UserDataT inst;inst = new aop2::UserDataT::?();inst.name = m.[]("name") is core::String ?{core::String} m.[]("name") : null;inst.city = m.[]("city") is core::String ?{core::String} m.[]("city") : null;inst.age = m.[]("age") is core::int ?{core::int} m.[]("age") : null;inst.squres = m.[]("squres") is core::double ?{core::double} m.[]("squres") : null;inst.sex = m.[]("sex") is core::bool ?{core::bool} m.[]("sex") : null;inst.houses = m.[]("houses") is core::Map<dynamic, dynamic> ?{core::Map<dynamic, dynamic>} block {core::Map<core::String, core::String> mymap;mymap = col::LinkedHashMap::from<core::String, core::String>(<core::String, core::String>{});for (core::String item in (m.[]("houses") as core::Map<dynamic, dynamic>).keys) {mymap.[]=(item, (m.[]("houses") as core::Map<dynamic, dynamic>).[](item) is core::String ?{core::String} (m.[]("houses") as core::Map<dynamic, dynamic>).[](item) : null);}} =>mymap : null;return inst;}

3. 應用暢想

基于Dill的Manipulation,我們可以實現(xiàn)往代碼中注入新的邏輯。比如閑魚科技之前開源的AOP庫AspectD的原理就是通過加載dill文件生成AST,然后遍歷AST,尋找到已經(jīng)annotation到的函數(shù)或語句,在dill層面操作后又生成dill參加到編譯器后續(xù)的流程,最終實現(xiàn)了AOP。

類似的,我們知道Dart對于Json解析操作不是很方便,jsonDecode不能直接生成業(yè)務對象,而是Map或者List之類的集合,還需要用戶自己手動代碼遍歷這些集合并裝載對象。雖然官方開源了一個基于Source_gen的方案,但使用上也不友好(還有其他一些方案如Dason等,但依賴于Mirror,詳見這里的比較)。其實遍歷Map或者List并裝配對象這樣的操作邏輯很簡單,我們也可以通過Dill Manipulation來做。

其使用方式簡便,舉例如下:

@JsonModel() class UserData {String name;String city;UserData son; }void main(){var str = '''{"name": "Jim","city": "hangzhou","son":{"name": "Kong","city":"Hangzhou"}}''';UserData userData = JsonDrill.fromJson<UserData>(jsonDecode(str));var map = JsonDrill.toJson<UserData>(userData);print("$map");}

更深入的思考一下,Dart現(xiàn)有的mirror能力至今未推薦使用(原因分析可參考這篇文章),那我們是否可以基于Dill Manipulation實現(xiàn)一個簡單輕量的LiteMirror庫呢?并基于這個LiteMirror庫實現(xiàn)更上層的Json解析和AOP甚至Hook能力?

當然,聰明的你或許已經(jīng)發(fā)現(xiàn),Dill Manipulation不可避免的要對編譯流程進行定制,這就要求比如在Flutter環(huán)境中,需要對Flutter Tool進行定制,以加入Dill再編輯的環(huán)節(jié)。劇透一下,閑魚科技目前就已經(jīng)實現(xiàn)了Json解析器,正在準備開源中,敬請期待


原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結

以上是生活随笔為你收集整理的编程界的“二向箔”——Dart元编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。