golang 自學系列(三)—— if,for,channel

来源:https://www.cnblogs.com/ms27946/archive/2020/03/04/golang-study-3.html
-Advertisement-
Play Games

golang 自學系列(三)—— if,for,channel 一般情況下,if 語句跟大多數語言的 if 判斷語句一樣,根據一個 boolean 表達式結果來執行兩個分支邏輯。 但凡總是有例外,go 語言還有這種寫法: 寫法 1 的意思是在判斷邏輯前,可以加一個表達式,比如獲取 ID 賦值給 i, ...


golang 自學系列(三)—— if,for,channel

一般情況下,if 語句跟大多數語言的 if 判斷語句一樣,根據一個 boolean 表達式結果來執行兩個分支邏輯。

但凡總是有例外,go 語言還有這種寫法:

// 寫法1
if i:= getID(); i < currentID {
    execute some logic
} else {
    execute some other logic
}

// 寫法2
var obj = map[string]interface{}
if val,ok := obj["id"]; ok {
    execute some logic
} else {
    execute some other logic
}

寫法 1 的意思是在判斷邏輯前,可以加一個表達式,比如獲取 ID 賦值給 i,然後參與後續的判斷是否小於當前 ID。

寫法 2 的意思同樣是在判斷邏輯前,可以加一個表達式,獲取對象 ID(obj["id"])給 val,但是與 1 不同的是,這裡 val、ok 的值是有直接關聯的。val 值取得成功與否,就是 ok 的結果值。

即 ok 一定是 boolean 類型值,表示 val = obj["id"] 是否賦值成功。我認為這種特性很好,完全不用取得值是否不存在,會報錯等。

for 語句

for 語句一般表示為重覆執行塊。由三個部分組成,一個是單條件控制的迭代,一個是 “for” 語句,最後一個是 “range” 語句。

ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
Condition = Expression .

for 查了資料才發現用法特別多

一. 使用單條件的 for 語句

for a < b {
    a *= 2
}

這個是最簡單的,意思就是只要你的條件計算得出來的是 true 就會重覆執行代碼段。就如上面所示,只要 a < b 就會一直會執行 a *= 2。相當於 while 死迴圈。

二. 使用 for 從句

// 句法格式
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
InitStmt = SimpleStmt .
PostStmt = SimpleStmt .

for i := 0; i < 10; i++ {
    f(i)
}

使用 for 從句的 for 語句也是通過條件控制的,但是會額外指定一個 init 以及 post 語句,就好比分配一個數,這個數會自增或遞減。滿足條件判斷,就會在重覆運行執行體。

只要初始化語句變數不為空,就會在第一次迭代運行之前計算。有幾點要註意:

for 從句中的任何元素都可以為空,除非它之後一個條件,否則這種情況下分號是不能丟的。如果條件是預設的,它就等價於這個條件是 true。例如

for condtion { exec() }  等同於 for ; condition ; { exec() }
for                  { exec() }  等同於 for   true          ; { exec() }

三. 使用 range 從句

使用了 range 從句的 for 語句代表從執行的這些對象,這些對象會是數組、分片、字元串或映射以及通道(channel)上接收的值。如果迭代的條目存在,就把它賦值給迭代變數。

RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .

這個表達式 “range” 的後邊的表達式被稱為 range 表達式,它可能是數組、數組指針、分片、字元串、映射(map)或者是通道接收操作(channel permitting receive operations.)。就像賦值一樣,如果左邊有操作數,那麼則必須是可定址的或是映射索引表達式。

如果範圍表達式是一個通道(channel),那麼最多只有一個迭代變數,否則最多有兩個變數。如果最後一個迭代變數是空標識符,那麼就相當於沒有這個標識符的 range 表達式。

range 表達式 x 要在迴圈體開始之前計算一次,有一個例外:如果存在最多一個迭代變數以及 len(x) 是常熟,那麼 range 表達式就不會計算。下麵是官網給出的例子

var testdata *struct {
    a *[7]int
}
for i, _ := range testdata.a {
    // testdata.a is never evaluated; len(testdata.a) is constant
    // i ranges from 0 to 6
    f(i)
}

var a [10]string
for i, s := range a {
    // type of i is int
    // type of s is string
    // s == a[i]
    g(i, s)
}

var key string
var val interface{}  // element type of m is assignable to val
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for key, val = range m {
    h(key, val)
}

// key == last map key encountered in iteration
// val == map[key]

var ch chan Work = producer()
for w := range ch {
    doWork(w)
}

// empty a channel
for range ch {}

Channel 類型

chan 關鍵字:起初這個官網沒有查到具體對 chan 的解釋,就只知道是一個關鍵字,後來經過一番資料查詢,發現這個是用來方便創建 channel 類型的快捷方式。其預設值是 nil。

既然知道 chan 是用來創建 channel 的,那麼我們就來看 channel 類型的定義:

A channel provides a mechanism for concurrently executing functions to communicate by sending and receiving values of a specified element type. The value of an uninitialized channel is nil.

就是說 channel 類型為併發運行函數提供一個機制,通過發送和接收指定元素類型的值通信。未分配的 channel 的值是 nil。

在來瞭解下 chan 的操作符 <-,它表示指定 channel 方向、發送或接收。如果沒有給定方向,就是雙向。channel 被限制只能通過賦值或顯示轉換來發送或接收。

chan T  // 可以用來發送和接收 T 類型的值
chan <- float64 // 只能被用於發送 64 位浮點數
<- chan int // 只能用於接收 int 數

官網還描述下麵這種用法,說實話我沒怎麼看懂

chan<- chan int    // same as chan<- (chan int)
chan<- <-chan int  // same as chan<- (<-chan int)
<-chan <-chan int  // same as <-chan (<-chan int)
chan (<-chan int)

go 語言提供內置函數 make 來構建新的 channel 值,該函數傳遞 channel 類型參數和一個可選的容量(capacity)參數值

make(chan int, 100)

其中的 100 是容量值(capacity),這個容量值是指 channel 內的緩衝大小。如果值為 0 說明沒有緩衝,這種情況下只有當接受者和發送者準備好才能成功通訊。否則,只要這個緩衝塊沒滿(推送)或不為空(接收),那已經緩衝的 channel 就能成功通信。

channel 能通過調用方法 close 關閉。多值賦值通過接收操作符的形式報告這個接收的值是否在 channel 在關閉之前。

單個 channel 能用在發送語句、接收操作符以及調用內置 cap 函數和 len 函數,也能在任意數量的 goroutline 使用,而不需要同步。通道是一個先進先出(FIFO)的隊列。

上面提到了兩點,發送語句和接收操作符

send 語句

簡單來講就是發送一個值給 channel。

ch <- 3 意思是發送一個值 3 給 channel 變數 ch。如果 channel 關閉了,會報 run-time panic 錯誤。

接收操作符

對於 channel 類型的操作數 ch,接收操作符的值 <- ch 意思是從 channel 類型值 ch 接收的值。<- 右邊是 channel 類型元素。表達式塊只有在值可用才不會阻塞。所以空 channel 無法接受值,因為永遠阻塞。

現在來看一下 chan 的一些例子

var c chan int  // nil
c = make(chan int)  // 初始化
fmt.Printf("c 的類型是%T \n", cc)   // chan int
fmt.Printf("c 的值是%v \n", cc)    //  0xc0000820c0

這能看出 chan int 的值是一個地址,像是指針一樣。不過目前我還是不知道這個具體的用法是什麼,用在什麼地方?

而當我嘗試讀取值的時候,卻發現好像一直在阻塞:

c <- 3
fmt.Printf("c 的值是%v \n", c)
<-c
fmt.Printf("c 的值是%v \n", c)

我想的是 chan 在發送時,沒有接收前是堵塞的,所以一直沒有執行下麵的輸出。所以我又在後面加了 <- c 讓 c 接收。結果發現還是不執行上面的輸出。

後來又查了相關的資料,得知 channel 類型很像是一個通道,消費者-生產者之間的關係。

於是我又寫了下麵代碼

cc := make(chan int)
defer close(cc)
cc <- 3 + 4
i := <-cc
fmt.Println(i)

斷電調試發現(如何在 vscode 斷電調試我稍微會另起文章說)程式運行到 cc <- 3 + 4 就不往下執行,進程也沒結束,說明是阻塞的。從之前的概念上將,cc 初始化出來的類型是沒有設置初始容量,即沒有緩存,難道在不能發送數據了?為了驗證想法,我在初始化 channel 的時候家了初始緩存 buffer:cc := make(chan int, 100);能正常輸出結果值。但是概念上並沒有說沒有緩衝區的就不能正常發送數據啊。

在描述 send 語句的時候說過,在接收器準備好了,發送器才會被處理。按照這個結果來看,接收器是沒有準備好的。那要怎麼才能使接收器準備好呢?

我又查了資料,發現基本上都是這麼種寫法,以上面的代碼為前提

cc := make(chan int)
defer close(cc)
go func() {
  cc <- 3 + 4
}()
i := <-cc
fmt.Println(i)

這樣就是正常的。難道要把發送器以一種函數調用的形式存在?

我又嘗試把立即執行函數改為普通函數

cc := make(chan int)
defer close(cc)
fchan(cc)
i := <-cc
fmt.Println(i)

結果發現還是不行,這個問題先放一邊吧。等以後有時間在仔細學習一下。

// TODO Range 也是可以處理 chan

初始化數組

[]type{} 當我看到這個語句的時候,我內心是奔潰的,因為突然看到這種寫法的我不知道這屬於哪個特征,都不好查關鍵字資料。剛開始我以為是 type 類型的數組,然後後面再接一個空對象 {}。但是翻遍了特性,都沒看到這種概念。後來直接寫了一個例子,查看具體的輸出

var sa = []string{}
fmt.Printf("sa 的值是%v \n", sa)   //sa 的值是[] 

發現它就是一個數組,並沒有什麼對象。後來我嘗試去掉後面 {} 發現根本通不過編譯,這才知道,這就是初始化一個 string 數組。

本文同步至:https://github.com/MarsonShine/GolangStudy/blob/master/src/QPaint/doc/golang-study-3.md


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 此段代碼通過Canvas元素實現了電影《黑客帝國》中進入Matrix的終端界面的一個動畫效果。 相容H5和各種版本的瀏覽器。可以在這裡看到線上效果, "點我,點我!" 在瀏覽器中打開,配上F11全屏效果,效果棒棒的! 在代碼的起始部分,使用了一個相容低版本瀏覽器的requestAnimationFr ...
  • 近期改版RXEditor,把改版過程,用到的技術點,記錄下來。昨天完成了靜態頁面的製作,製作過程並未詳細記錄,後期已經不願再補了,有些遺憾。不過工作成果完整保留在github上,地址:https://github.com/vularsoft/studio-ui 這個項目下麵的html-demo.ht ...
  • 隨機飄落一些花瓣,那麼這種效果用代碼怎麼實現的呢,下麵小編給大家詳解jquery實現網頁背景花瓣隨機飄落特效,需要的朋友可以參考下 飄花效果的實現——效果圖: 需求: 一個jquery,,,這個看標題麽就知道了 jQuery Transit還有這個東西 "http://github.com/rsta ...
  • 一、關於集合工具類 java.utils.Collections; Collections工具類可以對List集合中的元素進行排序,但是集合中的元素必須是“可以比較的”,實現Comparable介面。 package com.bjpowernode.java_learning; import jav ...
  • CPP 學習筆記 可以直接下載pdf CPP 學習筆記 0.1. 多線程 0.1.1. 文件操作已經學完,今天看下多線程 0.1.1.1. 知識點1 0.1.1.2. 代碼1 0.1.1.3. 知識點2 0.1.2. 知識點3 0.1.2.1. 代碼3 0.2. STL 0.2.1. STL 學習, ...
  • 1、面向對象技術簡介 類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。 方法:類中定義的函數。 類變數:類變數在整個實例化的對象中是公用的。類變數定義在類中且在函數體之外。類變數通常不作為實例變數使用。 數據成員:類變數或者實 ...
  • 基於SSM開發學生請假管理系統 開發環境: Windows操作系統開發工具: Eclipse+Jdk+Tomcat+MySql資料庫需求: 開發一個學生請假審批系統,在瀏覽器中打開運行,前端使用jsp以及jstl,後端使用Spring+SpringMVC+Mybatis。資料庫使用MySQL。所有使 ...
  • 基於JSP開發Java線上學習平臺系統開發環境: Windows操作系統開發工具:Myeclipse+Jdk+Tomcat7+MYSQL資料庫運行效果圖 源碼及原文鏈接:https://javadao.xyz/forum.php?mod=viewthread&tid=121 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...