GO學習之 微框架(Gin)

GO系列

1、GO學習之Hello World
2、GO學習之入門語法
3、GO學習之切片操作
4、GO學習之 Map 操作
5、GO學習之 結構體 操作
6、GO學習之 通道(Channel)
7、GO學習之 多線程(goroutine)
8、GO學習之 函數(Function)
9、GO學習之 接口(Interface)
10、GO學習之 網絡通信(Net/Http)
11、GO學習之 微框架(Gin)

文章目錄

  • GO系列
  • 前言
  • 一、Gin 簡介
  • 二、Gin 框架搭建
    • 2.1 安裝 Gin
    • 2.2 簡單示例
  • 三、路由和處理函數
    • 3.1 什么是路由?
    • 3.2 Gin 框架中的路由及案例
    • 3.3 實際開發中的應用及優缺點
  • 四、請求和響應處理
    • 4.1 接受參數
    • 4.2 處理請求
    • 4.3 生成響應
  • 五、中間件
    • 5.1 什么是中間件(Middleware)?
    • 5.2 中間件的作用及案例
      • 5.2.1 全局中間件
      • 5.2.2 局部中間件
    • 5.3 中間件的優缺點
  • 六、錯誤處理
    • 6.1 上下文存儲異常信息
    • 6.2 獲取異常信息
  • 七、總結

前言

按照公司目前的任務,go 學習是必經之路了,雖然行業卷,不過技多不壓身,依舊努力!!!
說起微服務框架,首當其沖的就是 JAVA 技術棧的 Spring Cloud 全家桶,吃過的人都說好,比較 Spring Cloud 已經可以說是完全能滿足互聯網后端開發需求,用 Spring Cloud 來搭建一個三高(高并發、高可用、高性能)的后端架構并非難事。
Spring Cloud:Zuul(路由)、Gateway(路由)、Eureka(注冊中心)、Hystrix(熔斷限流)、Config(配置中心)、Bus(事件,消息總線)、Sleuth(日志收集,鏈路追蹤)、Ribbon(負載均衡)、OpenFeign(API 調用) 等。
Spring Cloud Alibaba:Nacos(注冊配置中心)、Sentinel(限流降級)、Seata(分布式事務)、Stream(分布式消息)等。
那 Go 語言自然也會包容微服務的思想,Gin 就是 Go 語言中的一個微服務框架,是一個輕量級的、高性能的 Web 框架,為專門構建快速的 Web 應用和 API 而設計。

一、Gin 簡介

  • Gin 是一個輕量級的、高性能的 Web 框架,專門為構建快速的 Web 應用和 API 而設計。它是基于 Go 語言的標準庫,提供了簡單易用的 API 和許多有用的功能,開發者可以快速地構建和部署 Web 服務。
  • 強大的路由和中間件支持,Gin 提供了靈活的路由定義和中間件機制,可以方便的處理各種負責的邏輯。
  • 適用于構建 RESTful API,Gin 提供了 JSON 構建和解析響應功能,非常適合構建 RESTful 風格 API。

當然也有不足之處:

  • 功能相對簡化,相比一些成熟的 Web 框架,Gin 在一些方面較為簡化,如模板渲染等。
  • 社區相對較小,雖然 Gin 在國內擁有一定的用戶群體,但是相對 Spring 等其他 Web 框架,社區還是相對較小的。

二、Gin 框架搭建

在使用 Gin 框架之前,首先需要安裝 Gin 包,就類似 JAVA 中如果要用到 web 模塊就需要映入 starter-web 模塊。

2.1 安裝 Gin

通過如下命令來安裝:

go get github.com/gin-gonic/gin

安裝成功

2.2 簡單示例

下面是一個基于 Gin 寫的一個 簡單的 API 示例。

示例中,首先導入 “github.com/gin-gonic/gin” 包,并使用 gin.Default() 來創建一個默認的 Gin 引擎 router。然后使用 router 來定義了一個 路由,使用匿名函數來處理響應,返回了一個 Hello Gin 的相應字符串。最后使用 router.Run() 啟動這個 HTTP 服務。

package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {// 創建一個 Gin 引擎router := gin.Default()// 定義路由和處理函數,這里使用匿名函數router.GET("/", func(ctx *gin.Context) {ctx.String(http.StatusOK, "Hello Gin!!!")})// 啟動 HTTP 服務器router.Run("127.0.0.1:8080")
}

我們使用 go run hello.go 來運行,瀏覽器訪問測試:
訪問成功

三、路由和處理函數

3.1 什么是路由?

路由是指根據客戶端請求的 URL 路徑,將請求映射到相應的處理函數上,這里對比 SpringMVC 框架的 DispatcherServlet 控制中心。在 Web 應用中,當用戶訪問不同的 URL 路徑時,應用程序就需要調用相對于的處理函數來處理用戶的請求,每個請求的處理函數都有不同的業務邏輯,路由就會幫你將不同的請求分配到正確的處理函數上

在 Gin 框架中,你可以使用不同的 HTTP 方法(GET, POST, PUT, DELETE等)來定義不同的路由,并且為每一個路由指定一個處理函數。

3.2 Gin 框架中的路由及案例

Gin 框架中采用的路由是基于 httprouter 做的。
下面來看一個小小的示例:

下面示例中,通過 Gin 框架定義了 /hello GET 接口和 /add POST 接口,并且從請求體中獲取 name 參數。
我來來看,一個包中,我們可以定義不同路由已完成不同的請求操作。

package mainimport ("fmt""net/http""github.com/gin-gonic/gin"
)func main() {// 創建一個 Gin 引擎router := gin.Default()// 定義路由和處理函數,這里使用匿名函數router.GET("/hello", func(ctx *gin.Context) {// 從請求體中查詢 name 參數name := ctx.Query("name")fmt.Printf("接收到參數:%s", name)ctx.String(http.StatusOK, "Hello Gin! %s", name)})router.POST("/add", func(ctx *gin.Context) {var requestData struct {Name string "json:name binding:required"}// 使用 ShouldBindJSON 方法將請求體中的 JSON 數據綁定到結構體中if err := ctx.ShouldBindJSON(&requestData); err != nil {ctx.JSON(http.StatusBadRequest, gin.H{"error:": err.Error()})return}// 從結構體中獲取參數name := requestData.Nameif len(name) == 0 {fmt.Println("獲取name參數失敗!")ctx.String(http.StatusBadRequest, "add fail!")} else {fmt.Printf("添加操作:%+v 完成\n", name)ctx.String(http.StatusOK, "%s add successful!", name)}})// 啟動 HTTP 服務器router.Run("127.0.0.1:8080")
}

我們 Postman 來請求測試:
/hello GET 接口:
GET請求
/add POST 請求:
POST請求

3.3 實際開發中的應用及優缺點

在實際開發中,路由和函數處理運用非常廣泛,以下是一些例子:

  1. 頁面訪問:給頁面提供不同的 API 接口以供頁面獲取數據渲染,當用戶訪問不同的頁面或資源時,通過 URL 統一資源定位符 來調用不同的路由獲取資源。
  2. API 路由:除了前端頁面,其他客戶端比如:小程序、APP、給第三方系統提供接口等。

優點:

  • 組織結構清晰:路由可以將不同的請求和處理函數組織起來,以便代碼更加清晰。
  • 模塊化開發:可以實現模塊化開發,每個處理函數對應每個路由處理不同的業務請求。
  • 靈活性:路由可以通過不同的 URL 路徑調用處理不同的處理函數,實現靈活處理請求。

缺點:

  • 路由管理:如果規模龐大,路由管理可能變的復雜,需要合理地組織維護。
  • 路由沖突:在定義路由時,如果定義了相同的路由,可能會導致路由沖突。
  • 可讀性:如果路由過多或者命名不清晰,可能會降低代碼的可讀性。

四、請求和響應處理

在 Gin 框架中,請求和響應處理是開發 Web 應用的核心部分,也是程序猿日常做的最多的事情。
每開發一個API,逃不過這幾步驟:

4.1 接受參數

  • 獲取 Request Header 參數
token := ctx.GetHeader("token")
  • 獲取 Request Path 參數
id := ctx.Param("id")
  • 獲取 Request Param 參數
name := ctx.Query("name")
  • 獲取 Request Body 參數

在獲取 RequestBody 參數是,我們需要封裝結構體,然后綁定請求體到結構體中。

var requestData struct {Name string "json:name binding:required"
}
// 使用 ShouldBindJSON 方法將請求體中的 JSON 數據綁定到結構體中
if err := ctx.ShouldBindJSON(&requestData); err != nil {ctx.JSON(http.StatusBadRequest, gin.H{"error:": err.Error()})return
}
// 從結構體中獲取參數
name := requestData.Name

4.2 處理請求

在路由處理函數中,你可以執行你想要的處理邏輯。例如,你可以查詢數據庫、調用其他函數、處理數據等等。處理請求的邏輯在路由處理函數中實現,聲明處理函數或者使用匿名函數來處理。

4.3 生成響應

目前大多數的 Web 應用開發或者是系統之間相互調用、傳參、接受數據等大多都是 JSON 格式數據,那在 SpringMVC 框架中有做封裝,那在 Gin 框架中也是如此。

下面的案例中,我們通過 ctx.JSON() 方法向前端以 json 格式把數據返回,你可以將響應的數據封裝成一個 gin.H(類似 map)對象,然后使用 ctx.JSON 方法將其作為響應的主體返回給客戶端。

注意: 這里碰到一個小坑,忘記了 Go 語法中,小寫是沒有導出權限的,所以導致 postman 訪問,data 中總是 [] 的,詢問 大佬(chatGPT)才知道其中之奧妙,需大寫

package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {// 創建一個 Gin 引擎router := gin.Default()// 創建一個 Get 請求router.GET("/test/:id", func(ctx *gin.Context) {id := ctx.Param("id")name := ctx.Query("name")data := struct {// 注意,這里定義字段一定要大寫,要不然則不能導出,返回空Id   interface{} `json:"id"`Name string      `json:"name"`}{Id:   id,Name: name,}ctx.JSON(http.StatusOK, gin.H{"code": 200, "message": "請求成功", "data": data})})// 啟動服務router.Run(":8080")
}

在 postma 中測試

調用:http://127.0.01:8080/test/10?name=phen
響應:
{"code": 200,"data": {"id": "10","name": "phen"},"message": "請求成功"
}

當然,如果需要返回其他類型的響應,比如 HTML頁面、純文本等,可以使用 ctx.HTMLctx.String等方法,根據需要,設置適當的狀態碼和響應頭。

五、中間件

5.1 什么是中間件(Middleware)?

  • 中間件(Middleware)是一種常見的軟件設計模式,在 Web 開發中用于請求和響應之間添加自定義邏輯。
  • 中間件可以在請求到達處理函數之前或者在響應客戶端之前,對請求和響應做處理。
  • 在 Gin 框架中,中間件是一種非常重要的概念,用于處理一些通用的操作。
  • 如果知道 SpringMVC框架的話,就會知道 Filter 過濾器,Filter 有 Pre-proces 和 Post-process 操作,Gin 框架的中間件和 Filter 差不多。

5.2 中間件的作用及案例

中間件的作用對于請求和響應的進行預處理、后處理和記錄,以便實現如下功能(不限于):

  1. 身份驗證和授權:中間件中進行用戶身份驗證和授權,確保用戶能夠訪問特定資源。
  2. 日志記錄:可以在中間件中記錄 PV、用戶操作記錄等便于監控和排錯。
  3. 請求參數驗證:在中間件中可以進行參數驗證、XSS 攻擊過濾等,確保用戶提交的訂單數據合法。
  4. 緩存和性能優化:可以在中間件中進行熱數據的緩存,減少后端數據庫的壓力。
  5. 防爬機制:可以在中間件中對請求參數等進行校驗,以防別人通過接口爬數據。
  6. 請求耗時統計:中間件中記錄請求耗時,以便性能分析。

如何使用中間件呢:

5.2.1 全局中間件

在上面的案例中加入了中間件的使用,在下面的案例中,定義了一個 Logger() 函數來記錄請求日志,在 Logger() 函數中,首先記錄請求請求進入時間,調用 Next() 函數 繼續處理請求 最后記錄結束記錄時間和耗時。

package mainimport ("fmt""log""net/http""time""github.com/gin-gonic/gin"
)// 定義中間件處理函數,用戶記錄日志
func Logger() gin.HandlerFunc {// 使用自定義函數來處理return func(ctx *gin.Context) {fmt.Println("Middleware Logger Handler...")start := time.Now()// 調用 Next 繼續處理請求ctx.Next()end := time.Now()latency := end.Sub(start)log.Printf("[%s] 請求方法:%s 請求路徑:%s 耗時:%v", end.Format("2006-01-02 15:04:05"), ctx.Request.Method, ctx.Request.URL.Path, latency)}
}func main() {// 創建一個 Gin 引擎router := gin.Default()// 添加自定義的 Logger 中間件router.Use(Logger())// 定義路由和處理函數,這里使用匿名函數router.GET("/hello", func(ctx *gin.Context) {// 從請求體中查詢 name 參數name := ctx.Query("name")fmt.Printf("請求處理...接收到參數:%s \n", name)ctx.String(http.StatusOK, "Hello Gin! %s", name)})router.POST("/add", func(ctx *gin.Context) {var requestData struct {Name string "json:name binding:required"}// 使用 ShouldBindJSON 方法將請求體中的 JSON 數據綁定到結構體中if err := ctx.ShouldBindJSON(&requestData); err != nil {ctx.JSON(http.StatusBadRequest, gin.H{"error:": err.Error()})return}// 從結構體中獲取參數name := requestData.Nameif len(name) == 0 {fmt.Println("獲取name參數失敗!")ctx.String(http.StatusBadRequest, "add fail!")} else {fmt.Printf("添加操作:%+v 完成\n", name)ctx.String(http.StatusOK, "%s add successful!", name)}})// 啟動 HTTP 服務器router.Run("127.0.0.1:8080")
}

通過 Postman 請求測試:
中間件處理
從上面的截圖中可以看處,每次請求都調用到了中間件 Logger()。

5.2.2 局部中間件

上面是全局中間件,所有請求都會進入中間件,但是有時候并非所有請求都需要中間件處理,這時候就需要某幾個特殊的 API 接口實現中間件即可。

package mainimport ("errors""fmt""log""net/http""github.com/gin-gonic/gin"
)// 定義局部中間件函數,檢查用戶權限
func checkAuth() gin.HandlerFunc {return func(ctx *gin.Context) {token := ctx.Query("token")if len(token) == 0 {ctx.Error(errors.New("無權訪問"))ctx.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "無權訪問"})} else {log.Printf("請求方法:%s 請求路徑:%s 正常訪問", ctx.Request.Method, ctx.Request.URL.Path)}}
}func main() {// 創建一個 Gin 引擎router := gin.Default()router.GET("/list", checkAuth(), func(ctx *gin.Context) {errors := ctx.Errorsif errors != nil {ctx.Errors = nilreturn}data := struct {// 注意,這里定義字段一定要大寫,要不然則不能導出,返回空Id   interface{} `json:"id"`Name string      `json:"name"`}{Id:   1,Name: "phen",}fmt.Println("data: ", data)ctx.JSON(http.StatusOK, gin.H{"code": 200, "message": "請求成功", "data": data})})// 啟動 HTTP 服務器router.Run("127.0.0.1:8080")
}

通過瀏覽器訪問測試:
訪問成功:
訪問成功
無權訪問:
無權訪問
從兩張截圖中可以看出,有 token 則訪問成功,沒 token 則人訪問失敗!

注意、注意、注意:
這里遇到一個問題,第一次測試是我的代碼中沒有 ctx.Errors = nil 這句代碼,就發現如下情況:

  • 第一次訪問不帶 token 參數,自然無權訪問
  • 第二次訪問帶上 token, 沒有無權訪問,但是也沒有訪問成功結果
  • 為啥呢?chatGPT 告訴我

因為 Gin 框架上下文在一個請求中是共享的,所以在同一個請求的不同處理函數中,上下文中的數據和異常信息是可以共享的。
這種設計有助于在請求的不同處理階段中傳遞數據和異常信息,但也需要小心處理,以確保不會導致意外的結果。如果你想要在每次請求中使用一個干凈的上下文,可以在每個請求處理函數的開頭重新初始化上下文,或者在處理函數之間隔離上下文。
如果你不希望在不同請求之間共享異常信息,你可以在每次請求開始時,將上下文清空或初始化,以確保上下文不會受到之前請求的影響。

所以我加入了這句代碼 ctx.Errors = nil,每次訪問過之后清楚調異常信息,則每次訪問的時候,帶 token 則訪問成功,不帶則無權訪問,這樣的處理對于新手的我來說應該不是很合理,后面找大佬咨詢,或者哪位大佬看到了,評論區指導一下

5.3 中間件的優缺點

有點:

  • 代碼復用:中間件可以通過將公共的代碼邏輯提取出來,進行封裝,實現代碼的復用,避免相似邏輯和重復代碼。
  • 邏輯解耦:中間件可以將請求和處理邏輯解耦,是的代碼更加清晰、模塊化和易于維護。
  • 靈活性:中間件可以在不同的路由器上使用,在上面的案例中,/hello GET 和 /add POST 路由都使用了 Logger() 中間件。

缺點:

  • 復雜性:通過中間件處理,可能會增加業務的復雜性,不當使用會導致業務代碼難以理解。
  • 性能影響:每次請求都需要經過中間件,這樣中間件中邏輯如果過于復雜,可能影響請求API性能。

六、錯誤處理

Gin 框架中提供了一種簡便的方式來處理函數中發生的異常,確保錯誤能夠捕獲并且正確的返回給前端。

6.1 上下文存儲異常信息

在下面的案例中,定義了一個 failFunc() 函數,此函數的作用就是返回一個異常,當在 Get() 方法中獲取到的 err 時,則用 ctx.Error(err) 將錯誤信息存儲在 Gin 上下文中。這樣,Gin 框架會在請求處理完畢后,檢查是否有存儲的異常信息,如果有則把錯誤信息返回給前端。

package mainimport ("errors""net/http""github.com/gin-gonic/gin"
)func failFunc() error {return errors.New("運行異常")
}func main() {// 創建一個 Gin 引擎router := gin.Default()// 創建一個 Get 請求router.GET("/test/:id", func(ctx *gin.Context) {err := failFunc()if err != nil {// 將錯誤信息存儲在 Gin 上下文中ctx.Error(err)ctx.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "服務器異常"})return}ctx.JSON(http.StatusOK, gin.H{"code": 200, "message": "請求成功"})})// 啟動服務router.Run("127.0.0.1:8080")
}

通過 postman 調用測試:

請求:http://127.0.01:8080/test/10?name=phen
響應:
{"code": 500,"message": "服務器異常"
}

不過我發現,如果在出現異常是,也就是 err 不為空是,里面的 return 不要,則后面所有的 ctx.JSONctx.String等,都會成功放回,所以請求結果會如下:

請求:http://127.0.01:8080/test/10?name=phen
響應:
{"code": 500,"message": "服務器異常"
}{"code": 200,"message": "請求成功"
}請求結束

這一點不會像 Spring框架中,response 過之后,如果再 response 則會報錯。

總之,Gin 框架通過在 Gin 上下文中存儲錯誤信息的方式,提供了方法處理錯誤的機制,使得處理函數中的錯誤被捕獲并且能夠返回給前端。
這樣有助于用戶體驗和調試信息。

6.2 獲取異常信息

而也可以通過 ctx.Errors 獲取到所有運行中的異常信息

fmt.Println("運行時的所有異常:", ctx.Errors)

只要在 return 前通過 Errors() 方法獲取存儲在 Gin 中的異常信息,就可以拿到所有的運行過程中的異常,以便業務邏輯的判斷和處理。

七、總結

什么是微框架(Gin),Gin 框架是一個輕量級的,高性能的 Web 框架,專門為構架快速的 Web 應用和 API 而設計。它是基于 Go 語言的標準庫開發,提供簡單易用的 API 和其他更多的功能,開發者可以快速的構建出 Web 應用并且部署。
通過 go get github.com/gin-gonic/gin 來安裝 Gin 框架到開發者環境,通過 框架提供的 路由和處理函數來快速開發 API,接受參數通過函數處理業務邏輯,然后通過 Gin 框架提供的 JSON、String、HTML等方法返回給前端不同類型數據。
通過中間件來處理公共的業務邏輯,比如認證授權、日志記錄等。
也有異常處理機制,Gin 通過上下文存儲異常信息,然后把異常信息返回給前端來實現異常的處理機制,提高用戶體驗和調試信息。
最后,Gin 框架總算是有些入門了,后面繼續學習框架其他內容,然后博客分享。


現階段還是對 Go 語言的學習階段,想必有一些地方考慮的不全面,本文示例全部是親自手敲代碼并且執行通過。
如有問題,還請指教。
評論去告訴我哦!!!一起學習一起進步!!!

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

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

相關文章

UDS的DID(Data identification)

引言 DID是UDS中的一個重要概念,它代表著特定的數據標識符。DID用于標識和獲取ECU中的特定參數數據,如傳感器數據、狀態信息等。通過使用DID,診斷工具可以準確地獲取所需的數據,從而幫助診斷人員更好地了解車輛的狀態和性能。 D…

開發者必知:.gitignore 文件的魔法,助你管理項目文件如虎添翼!

前言: 在軟件開發的世界中,版本控制是一個至關重要的環節。而 Git 作為目前最流行的分布式版本控制系統之一,已經成為開發者不可或缺的工具。然而,在日常的開發過程中,有些文件是不適合被納入版本控制的,比…

leetcode242. 有效的字母異位詞

題目:leetcode242. 有效的字母異位詞 描述: 給定兩個字符串 s 和 t ,編寫一個函數來判斷 t 是否是 s 的字母異位詞。 注意:若 s 和 t 中每個字符出現的次數都相同,則稱 s 和 t 互為字母異位詞。 示例 1: 輸入: s “…

【React | 前端】在React的前端頁面中,判斷某個變量值是否被定義?根據是否定義顯示不同的內容?

問題描述 在React的前端頁面中,判斷某個變量值是否被定義?根據是否定義顯示不同的內容? 問題場景 假如,現在有一個需求是設計一個新功能,新功能中要求新增一個之前沒有的變量,假設是計算某一個數組的長度…

基于Java+SpringBoot+Vue的數碼論壇系統設計與實現(源碼+LW+部署文檔等)

博主介紹: 大家好,我是一名在Java圈混跡十余年的程序員,精通Java編程語言,同時也熟練掌握微信小程序、Python和Android等技術,能夠為大家提供全方位的技術支持和交流。 我擅長在JavaWeb、SSH、SSM、SpringBoot等框架…

【C語言】深度剖析數據在內存中的存儲

一、數據類型詳細介紹 1、數據類型介紹 (1)基本的內置類型 //內置類型就是C語言自帶的類型char //字符數據類型 short //短整型 int //整形 long //長整型 long long //更長的整形 float //單精度浮點數 double …

微信小程序使用rich-text解析富文本字符串的時候,遇到image標簽圖片很大超過屏幕

場景: 使用uniapp開發微信小程序,解析富文本文章需求 用到的組件: u-view2.0的u-parse uniapp提供的rich-text 以上兩種組件都是解析富文本的作用,一般用于富文本解析場景,比如解析文章內容,商品詳情&am…

桶排序-1184:明明的隨機數

【題目描述】 明明想在學校中請一些同學一起做一項問卷調查,為了實驗的客觀性,他先用計算機生成了N個1到1000之間的隨機整數(N≤100),對于其中重復的數字,只保留一個,把其余相同的數去掉&#x…

安防監控視頻匯聚平臺EasyCVR分發的FLV視頻流在VLC中無法播放是什么原因?

眾所周知,TSINGSEE青犀視頻匯聚平臺EasyCVR可支持多協議方式接入,包括主流標準協議國標GB28181、RTSP/Onvif、RTMP等,以及廠家私有協議與SDK接入,包括海康Ehome、海大宇等設備的SDK等。在視頻流的處理與分發上,視頻監控…

【jvm】jvm的生命周期

目錄 一、啟動二、執行三、退出 一、啟動 1.java虛擬機的啟動是通過引導類加載器bootstrap class loader創建一個初始類(initial class)來完成的,這個類是由虛擬機的具體實現指定的(根據具體虛擬機的類型) 二、執行 1.一個運行中的java虛擬機…

ORACLE行轉列、列轉行實現方式及案例

ORACLE行轉列、列轉行實現方式及案例 行轉列案例方式1.PIVOT方式2.MAX和DECODE方式3.CASE WHEN和GROUP BY 列轉行案例方式1.UNPIVOT方式2.UNION ALL 行轉列 案例 假設我們有一個名為sales的表,其中包含了產品銷售數據。表中有三列:product(…

FPGA實踐 ——Verilog基本實驗步驟演示

0x00 回顧:AND/OR/NOT 邏輯的特性 AND:與門可以具有兩個或更多的輸入,并返回一個輸出。當所有輸入值都為 1 時,輸出值為 1。如果輸入值中有任何一個為 0,則輸出值為 0。 OR:或門可以具有兩個或更多的輸入…

【python】-【】

文章目錄 轉義字符和原字符二進制與字符編碼標識符和保留字變量的定義和使用變量字符串列表for 一、print會輸出①數字②字符串(必須加引號)③含有運算符的表達式(例如 31 其中3,1是操作數,是運算符)&#…

vector的模擬實現

什么是vector vector是一個封裝了動態大小數組的順序容器跟任意其它類型容器一樣,它能夠存放各種類型的對象。 模擬實現 實現前的準備 在實現vector之前,為了和庫里的區分開需要將實現的vector放在一個自定義的命名空間里。而且vector需要實現成模版…

論文閱讀 - Neutral bots probe political bias on social media

論文鏈接:Neutral bots probe political bias on social media | EndNote Click 試圖遏制濫用行為和錯誤信息的社交媒體平臺被指責存在政治偏見。我們部署中立的社交機器人,它們開始關注 Twitter 上的不同新聞源,并跟蹤它們以探究平臺機制與用…

超導熱催生meme,換湯不換藥的投機輪回

文/章魚哥 出品/陀螺財經 幣圈對炒作meme概念的熱情從未消亡過。 隨著一種名為LK-99的物質被發現,圍繞超導的興奮不僅激發了科學界,加密貨幣相關概念也與之沸騰。不出所料,與此前圍繞元宇宙、AI大肆炒作一樣,許多meme代幣已經出現…

關于MySQL中的binlog

介紹 undo log 和 redo log是由Inno DB存儲引擎生成的。 在MySQL服務器架構中,分為三層:連接層、服務層(server層)、執行層(存儲引擎層) bin log 是 binary log的縮寫,即二進制日志。 MySQL…

android開發之Android 自定義滑動解鎖View

自定義滑動解鎖View 需求如下: 近期需要做一個類似屏幕滑動解鎖的功能,右劃開始,左劃暫停。 需求效果圖如下 實現效果展示 自定義view如下 /** Desc 自定義滑動解鎖View Author ZY Mail sunnyfor98gmail.com Date 2021/5/17 11:52 *…

數據結構——線性表

文章目錄 線性表的定義和基本操作順序表線性表的鏈式表示 線性表的定義和基本操作 線性表是具有相同數據類型的(n≥0)個數據元素的有限序列,其中n為表長,當n0時線性表是一個空表。若用L命名線性表,則其中一般表示為:L(a1,a2,a3, …

.NET實現解析字符串表達式

一、引子功能需求 我們創建了一個 School 對象&#xff0c;其中包含了教師列表和學生列表。現在&#xff0c;我們需要計算教師平均年齡和學生平均年齡。 //創建對象 School school new School() {Name "小菜學園",Teachers new List<Teacher>(){new Teach…