[Go] Template 使用簡介

Golang 提供了兩個標準庫用來處理模板?text/template?和?html/template。我們使用?html/template?格式化 html 字符。

模板引擎

模板引擎很多,Python 的 jinja,nodejs 的 jade 等都很好。所謂模板引擎,則將模板和數據進行渲染的輸出格式化后的字符程序。對于 Go,執行這個流程大概需要三步。

  1. 創建模板對象
  2. 加載模板字串
  3. 執行渲染模板

其中最后一步就是把加載的字符和數據進行格式化。其過程可以總結下圖:

warming up

Go 提供的標準庫?html/template?提供了很多處理模板的接口。我們的項目結構為:

├── main.go
└── templates├── index.html└── layout.html

templates 文件夾有兩個文件,分別為模板文件。?layout.html 文件如下:

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: {{ . }}</body>
</html>

我們可以使用 ParseFiles 方法加載模板,該方法會返回一個模板對象和錯誤,接下來就可以使用模板對象執行模板,注入數據對象。Go 的提供了一些模板標簽,稱之為?action,. 也是一種 action,更多的action 稍后解釋。

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("templates/layout.html")fmt.Println(t.Name())t.Execute(w, "Hello world")
}

我們打印了 t 模板對象的 Name 方法,實際上,每一個模板,都有一個名字,如果不顯示指定這個名字,Go 將會把文件名(包括擴展名當成名字)本例則是 layout.html。訪問之后可以看見返回的 html 字串:

$  curl -i http://127.0.0.1:8000/
HTTP/1.1 200 OK
Date: Fri, 09 Dec 2016 09:04:36 GMT
Content-Length: 223
Content-Type: text/html; charset=utf-8<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: Hello world</body>
</html>

Go 不僅可以解析模板文件,也可以直接解析模板字串,這就是標準的處理,新建 ->?加載 -> 執行 三部曲:

func templateHandler(w http.ResponseWriter, r *http.Request) {tmpl := `<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Go Web Programming</title></head><body>{{ . }}</body>
</html>`t := template.New("layout.html")t, _ = t.Parse(tmpl)fmt.Println(t.Name())t.Execute(w, "Hello World")
}

實際開發中,最終的頁面很可能是多個模板文件的嵌套結果。Go 的 ParseFiles 也支持加載多個模板文件,不過模板對象的名字則是第一個模板文件的文件名。

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ :=template.ParseFiles("templates/layout.html", "templates/index.html")fmt.Println(t.Name())t.Execute(w, "Hello world")
}

可見打印的還是 layout.html 的名字,執行的模板的時候,并沒有 index.html 的模板內容。

此外,還有 ParseGlob 方法,可以通過 glob 通配符加載模板。

模板命名與嵌套

模板命名

前文已經提及,模板對象是有名字的,可以在創建模板對象的時候顯示命名,也可以讓 Go 自動命名。可是涉及到嵌套模板的時候,該如何命名模板呢,畢竟模板文件有好幾個?

Go 提供了 ExecuteTemplate 方法,用于執行指定名字的模板。例如加載 layout.html 模板的時候,可以指定 layout.html

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ :=template.ParseFiles("templates/layout.html")fmt.Println(t.Name())t.ExecuteTemplate(w, "layout", "Hello world")
}

似乎和 Execute 方法沒有太大的差別。下面修改一下 layout.html 文件:

{{ define "layout" }}<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: {{ . }}</body>
</html>{{ end }}

在模板文件中,使用了 define 這個 action 給模板文件命名了。雖然我們 ParseFiles 方法返回的模板對象 t 的名字還是 layout.html, 但是 ExecuteTemplate 執行的模板卻是 html 文件中定義的layout。

不僅可以通過 define 定義模板,還可以通過 template action 引入模板,類似 jinja 的 include 特性。修改 layout.html 和 index.html

{{ define "layout" }}
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: {{ . }}{{ template "index" }}</body>
</html>
{{ end }}

index.html

{{ define "index" }}<div style="background: yellow">this is index.html
</div>{{ end }}

Go 的代碼也需要修改,使用 ParseFiles 加載需要渲染的模板文件:

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ :=template.ParseFiles("templates/layout.html", "templates/index.html")t.ExecuteTemplate(w, "layout", "Hello world")
}

訪問可以看到 index 被 layout 模板 include 了:

$ curl http://127.0.0.1:8000/<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: Hello world<div style="background: yellow">this is index.html</div></body>
</html>

單文件嵌套

總而言之,創建模板對象后和加載多個模板文件,執行模板文件的時候需要指定 base 模板(layout),在 base 模板中可以 include 其他命名的模板。無論點 .,define,template 這些花括號包裹的東西都是 Go 的 action(模板標簽)

Action

action 是 Go 模板中用于動態執行一些邏輯和展示數據的形式。大致分為下面幾種:

  1. 條件語句
  2. 迭代
  3. 封裝
  4. 引用

我們已經見識了 template 引用的用法,下面么再看看其他的用法

條件判斷

條件判斷的語法很簡單:

{{ if arg }}some content
{{ end }}{{ if arg }}some content
{{ else }}other content
{{ end }}

arg 可以是基本數據結構,也可以是表達式:if-end 包裹的內容為條件為真的時候展示。與 if 語句一樣,模板也可以有 else 語句。

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("templates/layout.html")rand.Seed(time.Now().Unix())t.ExecuteTemplate(w, "layout", rand.Intn(10) > 5)
}

layout.html 文件

{{ define "layout" }}
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: {{ . }}{{ if . }}Number is greater than 5!{{ else }}Number is 5 or less!{{ end }}</body>
</html>
{{ end }}

此時就能看見,當 . 的值為 true 的時候顯示 if 的邏輯,否則顯示 else 的邏輯。

迭代

對于一些數組,切片或者是 map,可以使用迭代的 action,與 Go 的迭代類似,使用 range 進行處理:

func templateHandler(w http.ResponseWriter, r *http.Request) {t := template.Must(template.ParseFiles("templates/layout.html"))daysOfWeek := []string{"Mon", "Tue", "Wed", "Ths", "Fri", "Sat", "Sun"}t.ExecuteTemplate(w, "layout", daysOfWeek)
}

layout.html 文件

{{ define "layout" }}
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: {{ . }}{{ range . }}<li>{{ . }}</li>{{ end }}</body>
</html>
{{ end }}

可以看見輸出了一堆 li 列表。迭代的時候,還可以使用 $ 設置循環變量:

{{ range $key, $value := . }}<li>key: {{ $key }}, value: {{ $value }}</li>
{{ else }}empty
{{ end }}

可以看見和迭代切片很像。range 也可以使用 else 語句:

func templateHandler(w http.ResponseWriter, r *http.Request) {t := template.Must(template.ParseFiles("templates/layout.html"))daysOfWeek := []string{}t.ExecuteTemplate(w, "layout", daysOfWeek)
}

layout.html 部分內容

{{ range . }}<li>{{ . }}</li>
{{ else }}empty
{{ end }}

當 range 的結構為空的時候,則會執行 else 分支的邏輯。

with封裝

with 語言在 Python 中可以開啟一個上下文環境。對于 Go 模板,with 語句類似,其含義就是創建一個封閉的作用域,在其范圍內,可以使用 . action,而與外面的 . 無關,只與 with 的參數有關:

{{ with arg }}
??? 此時的點 . 就是arg
{{ end }}

{{ define "layout" }}
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: {{ . }}{{ with "world"}}Now the dot is set to {{ . }}{{ end }}</body>
</html>
{{ end }}

訪問結果如下:

$ curl http://127.0.0.1:8000/<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: [Mon Tue Wed Ths Fri Sat Sun]Now the dot is set to world</body>
</html>

可見 with 語句的 . 與其外面的 . 是兩個不相關的對象。with 語句也可以有 else。else 中的 . 則和 with 外面的 . 一樣,畢竟只有 with 語句內才有封閉的上下文:

{{ with ""}}Now the dot is set to {{ . }}
{{ else }}{{ . }}
{{ end }}

訪問效果為:

$ curl http://127.0.0.1:8000/<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>template data: [Mon Tue Wed Ths Fri Sat Sun][Mon Tue Wed Ths Fri Sat Sun]</body>
</html>

引用

我們已經介紹了模板嵌套引用的技巧。引用除了模板的 include,還包括參數的傳遞。

func templateHandler(w http.ResponseWriter, r *http.Request) {t := template.Must(template.ParseFiles("templates/layout.html", "templates/index.html"))daysOfWeek := []string{"Mon", "Tue", "Wed", "Ths", "Fri", "Sat", "Sun"}t.ExecuteTemplate(w, "layout", daysOfWeek)
}

修改 layout.html, layout 中引用了 index 模板:

{{ define "layout" }}
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>layout template data: ({{ . }}){{ template "index" }}</body>
</html>
{{ end }}

index.html模板的內容也打印了?.:

{{ define "index" }}<div style="background: yellow">this is index.html ({{ . }})
</div>{{ end }}

訪問的效果如下,index.html 中的點并沒有數據。

$ curl http://127.0.0.1:8000/<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>layout template data: ([Mon Tue Wed Ths Fri Sat Sun])<div style="background: yellow">this is index.html ()
</div></body>
</html>

我們可以修改引用語句 {{ template "index" . }},把參數傳給子模板,再次訪問,就能看見 index.html 模板也有數據啦。

<div style="background: yellow">this is index.html ([Mon Tue Wed Ths Fri Sat Sun])
</div>

參數,變量和管道

模板的參數可以是go中的基本數據類型,如字串,數字,布爾值,數組切片或者一個結構體。在模板中設置變量可以使用?$variable := value。我們在 range 迭代的過程使用了設置變量的方式。

Go 還有一個特性就是模板的管道函數,熟悉 django 和 jinja 的開發者應該很熟悉這種手法。通過定義函數過濾器,實現模板的一些簡單格式化處理。并且通過管道哲學,這樣的處理方式可以連成一起。

{{ p1 | p2 | p3 }}

例如 模板內置了一些函數,比如格式化輸出:

{{ 12.3456 | printf "%.2f" }}

函數

既然管道符可以成為模板中的過濾器,那么除了內建的函數,能夠自定義函數可以擴展模板的功能。幸好 Go 的模板提供了自定義模板函數的功能。

想要創建一個定義函數只需要兩步:

  1. 創建一個 FuncMap 類型的 map,key 是模板函數的名字,value 是其函數的定義。
  2. 將?FuncMap 注入到模板中。
func templateHandler(w http.ResponseWriter, r *http.Request) {funcMap := template.FuncMap{"fdate": formDate}t := template.New("layout").Funcs(funcMap)t = template.Must(t.ParseFiles("templates/layout.html", "templates/index.html"))t.ExecuteTemplate(w, "layout", time.Now())
}

然后在模板中使用 {{ . | fdate }},當然也可以不適用管道過濾器,而是使用正常的函數調用形式,{{ fdate . }} 。

注意,函數的注入,必須要在 parseFiles 之前,因為解析模板的時候,需要先把函數編譯注入。

智能上下文

上面所介紹的特性,基本上是大多數模板引擎都具有的功能。Go 還提供了一個更有意思的特性。那就是根據上下文顯示模板的內容。例如字符的轉義,會根據所顯示的上下文環境而智能變化。比如同樣的 html 標簽,在 Js 和 html 環境中,其轉義的內容是不一樣的:

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("templates/layout.html")content := `I asked: <i>What's up?</i>`t.ExecuteTemplate(w, "layout", content)
}

模板文件:

{{ define "layout" }}
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>layout</title></head><body><h3>This is layout</h3>layout template data: ({{ . }})<div><a href="/{{ . }}">Path</a></div><div><a href="/?q={{ . }}">Query</a></div><div><a οnclick="f('{{ . }}')">Onclick</a></div></body>
</html>
{{ end }}

訪問結果

layout template data: (I asked: <i>What's up?</i>)<div><a href="/I%20asked:%20%3ci%3eWhat%27s%20up?%3c/i%3e">Path</a></div><div><a href="/?q=I%20asked%3a%20%3ci%3eWhat%27s%20up%3f%3c%2fi%3e">Query</a></div><div><a οnclick="f('I asked: \x3ci\x3eWhat\x27s up?\x3c\/i\x3e')">Onclick</a></div>

可以看見 Go 會自動為我們處理 html 標簽的轉義。這對 web 安全具有重要作用。避免了一些 XSS 攻擊。

XSS安全

安全是一個很大的話題,XSS 安全也包含很多內容,關于模板我們已經介紹了很多內容。XSS 安全就簡單介紹一下即可。

XSS 主要分為三種,我們先測試其中一種。即通過提交待 script 標簽的內容執行 js。例如下面的 html

layout.html 加一個表單

<form action="/" method="post">Comment: <input name="comment" type="text"><hr/><button id="submit">Submit</button>
</form>

一個最普通不過的表單。Go 的處理函數為:

func templateHandler(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("templates/layout.html")t.ExecuteTemplate(w, "layout", r.FormValue("comment"))
}

提交一段 js,可以看到 Go 在表達處理的時候,自動幫我們做了 xss 過濾

當然,如果不想轉義標簽,需要使用 template.HTML 方法包裹:

func templateHandler(w http.ResponseWriter, r *http.Request) {w.Header().Set("X-XSS-Protection", "0")t, _ := template.ParseFiles("templates/layout.html")t.ExecuteTemplate(w, "layout", template.HTML(r.FormValue("comment")))
}

開發者尤其要注意 XSS 的安全處理,然而 XSS 原不是這么簡單,更多的內容請閱讀安全相關的資料。

?


?

補充

顯示 字典 數據

package main
import ("fmt""html/template""net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("index.html")err := t.Execute(w, map[string]string{"Title": "My title", "Body": "Hi this is my body"})if err != nil {panic(err)}
}
func main() {http.HandleFunc("/", handler)http.ListenAndServe(":8080", nil)
}

index.html

Title is {{.Title}}

?


?

遇到的問題

// testtmpl.go
type UserInfo struct {Name string
}func main() {t := template.New("My Reporter")t, err := t.ParseFiles("views/report.html")if err != nil {fmt.Println("parse error")return}err = t.Execute(os.Stdout, UserInfo{Name: "tonybai"})if err != nil {fmt.Println("exec error", err)}return
}

執行結果,報錯:

go run testtmpl.go
exec error template: My Reporter: "My Reporter" is an incomplete or empty template; defined templates are: "report.html"

看起來似乎 template 對象與模板名字對不上導致的錯誤啊。修改一下:

t := template.New("report.html")

執行結果:

<html>
<head>
</head>
<body>Hello, tonybai
</body>
</html>

這回對了,看來 template 的名字在與 ParseFiles 一起使用時不是隨意取的,務必要與模板文件名字相同。

ParseFiles 支持解析多個文件,如果是傳入多個文件該咋辦?godoc 說了,template 名字與第一個文件名相同即可。

?

?

參考:

http://www.jianshu.com/p/05671bab2357

[鳥窩]Go 模板嵌套最佳實踐

[Tony Bai]近期遇到的3個Golang代碼問題

轉載于:https://www.cnblogs.com/52php/p/6412554.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/456425.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/456425.shtml
英文地址,請注明出處:http://en.pswp.cn/news/456425.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

內存泄露監測

2019獨角獸企業重金招聘Python工程師標準>>> iOS 內存泄露監測 144 作者 謝謝生活 已關注 2017.05.19 17:38* 字數 4235 閱讀 209評論 0喜歡 6 iOS可能存在的內存泄露&#xff1a;block 循環引用。當一個對象有一個block屬性&#xff0c;而block屬性又引用這個對象…

玩Azkaban跳過的坑

文章目錄一號坑&#xff1a;啟動Azkaban報錯&#xff1a;User xml file conf/azkaban-users.xml doesnt exist.二號坑&#xff1a;報錯&#xff1a;failed SslSocketConnector0.0.0.0:8443: java.io.FileNotFoundException: /home/hadoop/app/azkaban/azkaban-web-2.5.0/bin/ke…

兩種解除禁止右鍵、選中、復制的方法

我在網上找的 兩種解除禁止右鍵、選中、復制的方法 1、直接存到書簽點擊即可 javascript:(function(){var docdocument;var bddoc.body;bd.onselectstartbd.oncopybd.onpastebd.onkeydownbd.oncontextmenubd.onmousemovebd.onselectstartbd.ondragstartdoc.onselectstartdoc.o…

刪除節點removeChild()

http://www.imooc.com/code/1700 刪除節點removeChild() removeChild() 方法從子節點列表中刪除某個節點。如刪除成功&#xff0c;此方法可返回被刪除的節點&#xff0c;如失敗&#xff0c;則返回 NULL。 語法: nodeObject.removeChild(node) 參數: node &#xff1a;必需&…

機器學習自主解決安全威脅離我們還有多遠?

曾經聽見不止一次這樣的問題&#xff1a; “機器學習會替代基于人工經驗規則的安全解決方案么&#xff1f;”把這個問題放在去年來看&#xff0c;我們已經得到了非常多的討論甚至是一些已經實際應用的解決方案&#xff0c;對于人工智能在安全以及其它各種對數據進行價值挖掘的場…

Linux執行定時任務(crontab)遇到的坑

文章目錄前言&#xff1a;1、建立定時任務的兩種方式1.1、crontab -e1.2、vi /etc/ crontab2、兩種方法的區別2.1、用戶級2.2、系統級3、解決辦法前言&#xff1a; 之前第一次要在生產環境部署定時任務&#xff0c;無奈的是&#xff0c;博主對定時任務這塊還是個小白&#xff…

Vue:解決[Vue warn]: Failed to resolve directive: modle (found in Anonymous)

解決問題 [Vue warn]: Failed to resolve directive: modle (found in <ComponentA>) console.error(("[Vue warn]: " msg trace)); 原因是 我把model 寫成了 modle 這類錯誤一般是單詞寫錯了 (found in <Anonymous>) 解決思路

Oracle樹查詢及相關函數

Oracle樹查詢的最重要的就是select...start with... connect by ...prior 語法了。依托于該語法&#xff0c;我們可以將一個表形結構的中以樹的順序列出來。在下面列述了Oracle中樹型查詢的常用查詢方式以及經常使用的與樹查詢相關的Oracle特性函數等&#xff0c;在這里只涉及到…

Mysql常用函數總結

文章目錄前言&#xff1a;1、日期相關函數1.1、mysql獲取未來、現在、過去的時間&#xff1a;DATE_SUB&#xff08;&#xff09;、DATE_ADD()1.2、格式化日期&#xff1a;date_format&#xff08;&#xff09;1.3、MySQL 日期、時間相減函數&#xff1a;datediff(date1,date2),…

一行Python代碼制作動態二維碼

目錄 1、普通二維碼 2、藝術二維碼 3、動態二維碼 在GitHub上發現了一個比較有意思的項目&#xff0c;只需要一行Python代碼就可以快捷方便生成普通二維碼、藝術二維碼(黑白/彩色)和動態GIF二維碼。 GitHub網站參加&#xff1a;https://github.com/sylnsfar/qrcode 用法比…

Vue常用經典開源項目匯總參考-海量

Vue常用經典開源項目匯總參考-海量 Vue是什么&#xff1f; Vue.js&#xff08;讀音 /vju?/, 類似于 view&#xff09; 是一套構建用戶界面的 漸進式框架。與其他重量級框架不同的是&#xff0c;Vue 采用自底向上增量開發的設計。Vue 的核心庫只關注視圖層&#xff0c;并且非常…

鼠標移入視頻播放,鼠標移出播放停止,恢復到原來狀態

<!doctype html> <html lang"en"> <head><meta charset"UTF-8"><title>鼠標移入視頻播放&#xff0c;鼠標移出播放停止&#xff0c;恢復到原來狀態</title><link rel"shortcut icon" href"http://f…

Pycharm常用高效技巧總結

文章目錄1、PyCharm如何自動生成函數注釋2、pycharm運行程序時在Python console窗口中運行3、Pycharm在創建py文件時,如何自動添加文件頭注釋4、Pycharm配置遠程調試5、pycharm同一目錄下無法import明明已經存在的.py文件1、PyCharm如何自動生成函數注釋 一般在函數def()行下敲…

EntityFramework中常用的數據刪除方式

最近在學EF&#xff0c;目前了解到刪除操作有三種方式&#xff0c; 第一&#xff0c;官方推薦的先查詢數據&#xff0c;再根據查詢的對象&#xff0c;刪除對象。 這是第一種&#xff0c;官方推薦 第二&#xff0c;自己創建一個對象&#xff0c;然后附加&#xff0c;然后刪除。 …

Elasticsearch的前后臺運行與停止(tar包方式)

備注&#xff1a;在生產環境中&#xff0c;往往一般用后臺來運行。jps查看。 1、ES的前臺運行 [hadoopdjt002 elasticsearch-2.4.3]$ pwd/usr/local/elasticsearch/elasticsearch-2.4.3[hadoopdjt002 elasticsearch-2.4.3]$ bin/elasticsearch 2、ES的后臺運行 [hadoopdjt002 e…

解決pycharm運行Flask指定ip、端口更改無效

后來查了一下官網文檔&#xff0c;原來Flask 1.0 版本不再支持之前的FLASK_ENV 環境變量了。 Prior to Flask 1.0 the FLASK_ENV environment variable was not supported and you needed to enable debug mode by exporting FLASK_DEBUG1. This can still be used to control…

Freeswitch總結大全

文章目錄1、Freeswitch安裝2、Freeswitch中文文檔3、Freeswitch的event socket event list的中文簡介4、freeswitch之sip協議的注冊、呼叫、掛斷流程5、Freeswitch之mod_cdr_csv6、一款第三方收費的mod_vad&#xff08;看介紹挺不錯的&#xff0c;有做語音交互的童鞋可以看下&a…

Android中SimpleAdapter的使用—自定義列表

本人初學Android&#xff0c;今天研究到Adapter這塊感覺挺有意思的&#xff0c;寫了個自定義列表進行測試 首先我們新建一個layout列表布局文件&#xff0c;具體布局可以自己設定。 下面貼上我的自定義布局文件代碼 1 <?xml version"1.0" encoding"utf-8&qu…

Module 的語法

Module 的語法 概述嚴格模式export 命令import 命令模塊的整體加載export default 命令export 與 import 的復合寫法模塊的繼承跨模塊常量import()概述 歷史上&#xff0c;JavaScript 一直沒有模塊&#xff08;module&#xff09;體系&#xff0c;無法將一個大程序拆分成互相依…

解決:SyntaxError: Non-UTF-8 code starting with '\xe6' in file

pycharm加注釋報錯SyntaxError: Non-UTF-8 code starting with \xe6 in file 處理 代碼最上面加上編碼格式 #coding:utf-8