GScript?編寫標(biāo)準(zhǔn)庫(kù)示例詳解
版本更新
最近 GScript
更新了 v0.0.11
版本,重點(diǎn)更新了:
Docker
運(yùn)行環(huán)境- 新增了 byte 原始類型
- 新增了一些字符串標(biāo)準(zhǔn)庫(kù)
Strings/StringBuilder
- 數(shù)組切片語(yǔ)法:
int[] b = a[1: len(a)];
引言
前段時(shí)間發(fā)布了 GScript
的在線 playground
,
這是一個(gè)可以在線運(yùn)行 GScript
腳本的網(wǎng)站,其本質(zhì)原理是接收用戶的輸入源碼從而在服務(wù)器上運(yùn)行的服務(wù);這簡(jiǎn)直就是后門大開的 XSS
攻擊,為保住服務(wù)器我設(shè)置了運(yùn)行 API
的后端服務(wù)的用戶權(quán)限,這樣可以避免執(zhí)行一些惡意的請(qǐng)求。
但也避免不了一些用戶執(zhí)行了一些耗時(shí)操作,比如一個(gè)死循環(huán)、或者是我提供 demo
里的打印楊輝三角。
這本質(zhì)上是一個(gè)遞歸函數(shù),當(dāng)打印的三角層數(shù)過(guò)高時(shí)便會(huì)非常耗時(shí),同時(shí)也非常消耗 CPU。
有幾次我去檢查服務(wù)器時(shí)發(fā)現(xiàn)了幾個(gè) CPU 過(guò)高的進(jìn)程,基本上都是這樣的耗時(shí)操作,不可避免的會(huì)影響到服務(wù)器的性能。
使用 Docker
為了解決這類問(wèn)題,很自然的就能想到可以使用 Docker
,所有的資源都和宿主機(jī)是隔離開的,無(wú)論怎么瞎折騰也不會(huì)影響到宿主機(jī)。
說(shuō)干就干,最后修改了 API 執(zhí)行腳本的地方:
string fileName = d.unix("Asia/Shanghai") + "temp.gs" ; s.writeFile(fileName, body, 438); string pwd = s.getwd(); // string res = s.command("gscript", fileName); string res = s.command("docker","run","--rm","-v", pwd+":/usr/src/gscript","-w","/usr/src/gscript", "crossoverjie/gscript","gscript", fileName); s.remove(fileName); r.body = res; r.ast = dumpAST(body); r.symbol=dumpSymbol(body); ctx.JSON(200, r);
主要修改的就是將直接執(zhí)行的 GScript
命令修改為了調(diào)用 docker
執(zhí)行。
但其實(shí)也還有改進(jìn)空間,后續(xù)新增協(xié)程之后可以便可監(jiān)控運(yùn)行時(shí)間,超時(shí)后便會(huì)自動(dòng) kill 進(jìn)程。
我也將該 Docker
上傳到了 DockerHub
,現(xiàn)在大家想在本地體驗(yàn) GScript
的 REPL
時(shí)也只需要運(yùn)行Docker
就能使用。
docker pull crossoverjie/gscript docker run --rm -it crossoverjie/gscript:latest gscript
當(dāng)然也可以執(zhí)行用 Docker
執(zhí)行 GScript
腳本:
docker run --rm -v $PWD:/usr/src/gscript -w /usr/src/gscript crossoverjie/gscript gscript {yourpath}/temp.gs
編寫 GScript 標(biāo)準(zhǔn)庫(kù)
接下來(lái)重點(diǎn)聊聊 GScript
標(biāo)準(zhǔn)庫(kù)的事情,其實(shí)編寫標(biāo)準(zhǔn)庫(kù)是一個(gè)費(fèi)時(shí)費(fèi)力的事情。
現(xiàn)在編譯器已經(jīng)提供了一些可用的內(nèi)置函數(shù),借由這些內(nèi)置函數(shù)寫一些常見的工具類是完全沒有問(wèn)題的。
對(duì)寫 GScript
標(biāo)準(zhǔn)庫(kù)感謝的朋友可以當(dāng)做一個(gè)參考,這里我打了一個(gè)樣,先看下運(yùn)行效果:
// 字符串工具類 StringBuilder b = StringBuilder(); b.writeString("10"); b.writeString("20"); int l = b.writeString("30"); string s = b.String(); printf("s:%s, len=%d ",s,l); assertEqual(s,"102030"); byte[] b2 = toByteArray("40"); b.WriteBytes(b2); s = b.String(); assertEqual(s,"10203040"); println(s); // Strings 工具類 Strings s = Strings(); string[] elems = {"name=xxx","age=xx"}; string ret = s.join(elems, "&"); println(ret); assertEqual(ret, "name=xxx&age=xx"); bool b = s.hasPrefix("http://www.xx.com", "http"); println(b); assertEqual(b,true); b = s.hasPrefix("http://www.xx.com", "https"); println(b); assertEqual(b,false);
其中的實(shí)現(xiàn)源碼基本上是借鑒了 Go 的標(biāo)準(zhǔn)庫(kù),先來(lái)看看 StringBuilder
的源碼:
class StringBuilder{ byte[] buf = [0]{}; // append contents to buf, it returns the length of s int writeString(string s){ byte[] temp = toByteArray(s); append(buf, temp); return len(temp); } // append b to buf, it returns the length of b. int WriteBytes(byte[] b){ append(buf, b); return len(b); } // copies the buffer to a new. grow(int n){ if (n > 0) { // when there is not enough space left. if (cap(buf) - len(buf) < n) { byte[] newBuf = [len(buf), 2*cap(buf)+n]{}; copy(newBuf, buf); buf = newBuf; } } } string String(){ return toString(buf); } }
主要就是借助了原始的數(shù)組類型以及 toByteArray/toString
字節(jié)數(shù)組和字符串的轉(zhuǎn)換函數(shù)實(shí)現(xiàn)的。
class Strings{ // concatenates the elements of its first argument to create a single string. The separator // string sep is placed between elements in the resulting string. string join(string[] elems, string sep){ if (len(elems) == 0) { return ""; } if (len(elems) == 1) { return elems[0]; } byte[] bs = toByteArray(sep); int n = len(bs) * (len(elems) -1); for (int i=0; i < len(elems); i++) { string s = elems[i]; byte[] bs = toByteArray(s); n = n + len(bs); } StringBuilder sb = StringBuilder(); sb.grow(n); string first = elems[0]; sb.writeString(first); string[] remain = elems[1:len(elems)]; for(int i=0; i < len(remain); i++){ sb.writeString(sep); string r = remain[i]; sb.writeString(r); } return sb.String(); } // tests whether the string s begins with prefix. bool hasPrefix(string s, string prefix){ byte[] bs = toByteArray(s); byte[] bp = toByteArray(prefix); return len(bs) >= len(bp) && toString(bs[0:len(bp)]) == prefix; } }
Strings
工具類也是類似的,都是一些內(nèi)置函數(shù)的組合運(yùn)用;
在寫標(biāo)準(zhǔn)庫(kù)的過(guò)程中還會(huì)有額外收獲,可以再次閱讀一遍 Go 標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn)流程,換了一種語(yǔ)法實(shí)現(xiàn)出來(lái),會(huì)加深對(duì) Go 標(biāo)準(zhǔn)庫(kù)的理解。
所以歡迎感興趣的朋友向 GScript
貢獻(xiàn)標(biāo)準(zhǔn)庫(kù),由于我個(gè)人精力有限,實(shí)現(xiàn)過(guò)程中可能會(huì)發(fā)現(xiàn)缺少某些內(nèi)置函數(shù)或數(shù)據(jù)結(jié)構(gòu),這也沒關(guān)系,反饋 issue
后我會(huì)盡快處理。
由于目前 GScript
還不支持包管理,所以新增的函數(shù)可以創(chuàng)建 Class
來(lái)實(shí)現(xiàn),后續(xù)支持包或者是 namespace
之后直接將該 Class
遷移過(guò)去即可。
本文相關(guān)資源鏈接
- GScript 源碼:github.com/crossoverJi…
- Playground 源碼:github.com/crossoverJi…
- GScript Docker地址:hub.docker.com/r/crossover…
以上就是GScript 編寫標(biāo)準(zhǔn)庫(kù)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于GScript 編寫標(biāo)準(zhǔn)庫(kù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go 自定義package包設(shè)置與導(dǎo)入操作
這篇文章主要介紹了Go 自定義package包設(shè)置與導(dǎo)入操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05詳解Go語(yǔ)言如何利用高階函數(shù)寫出優(yōu)雅的代碼
高階函數(shù)(Hiher-order?Function)定義為:滿足下列條件之一的函數(shù):接收一個(gè)或多個(gè)函數(shù)作為參數(shù);返回值是一個(gè)函數(shù)。本文為大家介紹了如何利用高階函數(shù)寫出優(yōu)雅的代碼,希望對(duì)大家有所幫助2023-01-01Go 如何基于IP限制HTTP訪問(wèn)頻率的方法實(shí)現(xiàn)
這篇文章主要介紹了Go 如何基于IP限制HTTP訪問(wèn)頻率的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11GO語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)的方法
這篇文章主要介紹了GO語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)的方法,實(shí)例分析了Go語(yǔ)言實(shí)現(xiàn)TCP服務(wù)的技巧,需要的朋友可以參考下2015-03-03