日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Go語言一次真實(shí)的錯誤吞并的教訓(xùn)

在幾天前寫的代碼中,犯了幾個(gè)比較典型的錯誤,帶來不小的麻煩。特在此復(fù)現(xiàn)一下,吸取教訓(xùn)。

成都創(chuàng)新互聯(lián)是創(chuàng)新、創(chuàng)意、研發(fā)型一體的綜合型網(wǎng)站建設(shè)公司,自成立以來公司不斷探索創(chuàng)新,始終堅(jiān)持為客戶提供滿意周到的服務(wù),在本地打下了良好的口碑,在過去的十年時(shí)間我們累計(jì)服務(wù)了上千家以及全國政企客戶,如成都辦公空間設(shè)計(jì)等企業(yè)單位,完善的項(xiàng)目管理流程,嚴(yán)格把控項(xiàng)目進(jìn)度與質(zhì)量監(jiān)控加上過硬的技術(shù)實(shí)力獲得客戶的一致贊譽(yù)。

情景描述

代碼中需要實(shí)現(xiàn)一個(gè)客戶端與服務(wù)器的數(shù)據(jù)重傳機(jī)制,通過write寫數(shù)據(jù)給服務(wù)器,read讀取服務(wù)器返回。一旦中途發(fā)生錯誤,每隔1s就嘗試重新寫讀數(shù)據(jù)。當(dāng)超過上下文時(shí)間,重傳失敗。重傳實(shí)現(xiàn)代碼retry如下。

 
 
 
  1. func retry(ctx context.Context) (data string, err error) { 
  2.  
  3. LOOP: 
  4.  for i:=1;;i++{ 
  5.   err = write() 
  6.   if err == nil{ 
  7.    res, err := read() 
  8.    if err == nil{ 
  9.     data = string(res) 
  10.     return data, err 
  11.    } 
  12.   } 
  13.  
  14.   log.Printf("change data failed, err: %v, retry times : %d\n", err, i) 
  15.  
  16.   select { 
  17.   case <-ctx.Done(): 
  18.    log.Printf("retry failed") 
  19.    break LOOP 
  20.   case <-time.After(1 * time.Second): 
  21.   } 
  22.  } 
  23.  return "", err 

讀寫服務(wù)器數(shù)據(jù)函數(shù)和調(diào)用重傳代碼mock如下。

 
 
 
  1. func write() error { 
  2.  return nil 
  3.  
  4. func read() ([]byte, error) { 
  5.  return []byte("hello world"), errors.New("this is a error") 
  6.  
  7. func main() { 
  8.  ctx,_ := context.WithTimeout(context.Background(),5*time.Second) 
  9.  _, _ = retry(ctx) 
  10.  time.Sleep(10*time.Second) 

write返回err為nil,read有非nil返回。這種情況下,日志輸出如下。

 
 
 
  1. 2020/07/05 09:30:57 change data failed, err: , retry times : 1 
  2. 2020/07/05 09:30:58 change data failed, err: , retry times : 2 
  3. 2020/07/05 09:30:59 change data failed, err: , retry times : 3 
  4. 2020/07/05 09:31:00 change data failed, err: , retry times : 4 
  5. 2020/07/05 09:31:01 change data failed, err: , retry times : 5 
  6. 2020/07/05 09:31:02 retry failed 

原因分析

可以看到的是,如預(yù)想的一樣:當(dāng)發(fā)生錯誤時(shí),就重新嘗試write和read。即重傳機(jī)制生效。但是,日志中為何err會為nil,read方法的錯誤返回被吞掉了?

經(jīng)過排查,發(fā)現(xiàn)原因就在于——Go語法糖:=(短變量聲明)的不當(dāng)使用。

 
 
 
  1. err = write() 
  2.  if err == nil{ 
  3.   res, err := read() 
  4.   if err == nil{ 
  5.    data = string(res) 
  6.    return data, err 
  7.   } 
  8.  } 
  9.  
  10.  log.Printf("change data failed, err: %v, retry times : %d\n", err, i) 

在retry中,err是已被聲明的變量類型error。由于read返回的是兩個(gè)變量,故小菜刀在此利用短變量聲明res變量,接受read的第一個(gè)返回參數(shù)。但是,此舉會改變err的作用范圍:err成為了一個(gè)局部變量。什么意思呢?即此時(shí)的err被短變量聲明所作用,成為了新聲明對象,它只能作用于內(nèi)部區(qū)域了。對于外部log.Printf而言,其引用到的err還是write方法生成的err對象。因此,即使read方法返回的err不為空,log.Printf打印的還是write方法的err結(jié)果,導(dǎo)致read的err內(nèi)容被吞。

因此,為了避免此類錯誤發(fā)生,相應(yīng)代碼調(diào)整如下。

 
 
 
  1. var res []byte 
  2.  res, err = read() 
  3.  if err == nil{ 
  4.   data = string(res) 
  5.   return data, err 
  6.  } 

此時(shí),當(dāng)read返回err非nil時(shí),日志打印如下。

 
 
 
  1. 2020/07/05 09:46:16 change data failed, err: this is a error, retry times : 1 
  2. 2020/07/05 09:46:17 change data failed, err: this is a error, retry times : 2 
  3. 2020/07/05 09:46:18 change data failed, err: this is a error, retry times : 3 
  4. 2020/07/05 09:46:19 change data failed, err: this is a error, retry times : 4 
  5. 2020/07/05 09:46:20 change data failed, err: this is a error, retry times : 5 
  6. 2020/07/05 09:46:21 retry failed 

總結(jié)

一、Go語法糖——短變量聲明(:=)使用注意事項(xiàng)。

  • :=表示聲明+賦值。
  •  短變量聲明不需要聲明所有在左邊的變量。如果一些變量在同一個(gè)詞法塊中聲明,那么對于這些變量,短聲明的行為等同于賦值(同時(shí)更改了這些變量的作用域)。

二、異常判斷規(guī)則

在上述場景代碼中,是一個(gè)多層級條件判斷的情形,其判斷規(guī)則是err為nil。但這是一種不恰當(dāng)?shù)奶幚磉壿嫛:侠淼呐袛鄺l件,是對異常情況作判斷,而將正常邏輯置于條件之外。那么,修改后的retry條件判斷邏輯應(yīng)該如下所示。

 
 
 
  1. func retry(ctx context.Context) (data string, err error) { 
  2.  
  3. LOOP: 
  4.  for i:=1;;i++{ 
  5.   err = write() 
  6.   if err != nil{ 
  7.    log.Printf("write data failed, err: %v, retry times : %d\n", err, i) 
  8.    select { 
  9.    case <-ctx.Done(): 
  10.     log.Printf("retry failed") 
  11.     break LOOP 
  12.    case <-time.After(1 * time.Second): 
  13.    } 
  14.    continue 
  15.   } 
  16.  
  17.   res, err := read() 
  18.   if err != nil{ 
  19.    log.Printf("read data failed, err: %v, retry times : %d\n", err, i) 
  20.    select { 
  21.    case <-ctx.Done(): 
  22.     log.Printf("retry failed") 
  23.     break LOOP 
  24.    case <-time.After(1 * time.Second): 
  25.    } 
  26.    continue 
  27.   } 
  28.  
  29.   data = string(res) 
  30.   return data, err 
  31.  
  32.  } 
  33.  return "", err 

這樣,正常的處理流程,其主邏輯均在最外層,只有異常情況(err!=nil)才進(jìn)入異常處理邏輯。當(dāng)采用這種判斷規(guī)則之后,就不存在多層條件嵌套語句,由語法糖帶來的問題,也不復(fù)存在。


當(dāng)前標(biāo)題:Go語言一次真實(shí)的錯誤吞并的教訓(xùn)
網(wǎng)站鏈接:http://www.5511xx.com/article/cdoochh.html