P75 今日内容
P76内容回顧
一個檔案夾就是一個包,包裡都是.go檔案。
包導入的時候可以起别名,可以匿名導入包。
包裡面的辨別符,需要首字母大寫,才被外部可見,可以調用
包導入的路徑,是從$GOpath的src後面的路徑開始寫起
init是包導入的時候會自動執行,一個包裡隻有一個init,init沒有參數也沒有傳回值,也不能手動調用,一般用于初始化操作,一般初始化配置檔案,資料庫連結等。
**接口是一種特殊類型,是你要實作的方法的清單。
實作了接口的方法就實作了這個接口,就可以作為這個接口類型的變量。
**
空接口,代表了一個接口裡沒有方法清單,一個方法都沒有,那麼所有類型都實作了一個空接口,可以把任何類型存到空接口裡,interFace{}表示一個空接口。
一般作為函數參數,fmt.println就是 一個空接口 ,或者map裡想存任意類型的值可以用空接口
接口底層其實分兩部分,一個 動态類型,一個動态值,類型斷言就是判斷類型是什麼類型的。前提是判斷的類型是個接口類型的變量。
T大t一般在go語言裡代表type。
interface{}就代表一個空接口。
有多個判斷,可以使用switch,現在隻能猜,用了反射才能知道确切的類型
檔案操作,打開關閉,讀寫,程式也是通過系統調用去操作檔案,如果不釋放io,就會讓作業系統資源耗盡。正常大公司伺服器都是3年報廢,或者退居2線,重要的生産三天兩頭出問題,誰也受不了了。
打開一個問獲得檔案對象,如果錯誤傳回錯誤碼,判斷錯誤的時候不為空,就一定有錯誤
要用下面的方式寫,go語言可以有多個傳回值,如果f1上面的錯誤了,那麼fileobj就是nil,nil就沒有close方法,就傳回給你一個空指針引用
讀檔案三種方法,bufio會有一個中間狀态,緩沖區,讀到緩沖區,達到緩沖區的門檻值就傳回到代碼。寫的時候緩沖區調用flush才能寫,但是中間斷電,資料就丢了
P77 在檔案中間插入内容
所有檔案相關的操作都可以在标準庫裡查找。
seek(1,0)1個位元組,從0開始,讀一個切片
windows這裡有/r/n
是以 需要移動三個字元,光标移動到b,3代表移動三個位置,0代表從什麼地方開始
像這樣不換行就會讀到b了
往檔案裡寫,需要額外聲明一個切片,拿到上面讀到的切片。
切片初始化隻能用make,不能用new
這樣就相當于往檔案寫了C
相當于把原來的b覆寫了
插入資料的話,隻能先建立一個檔案,讀出來,再出入到新的檔案裡,所有語言都不可能讀一個檔案,從中間插入資料。
讀檔案寫入臨時檔案,再寫入要插入的内容,
緊接着把源檔案後續的内容寫入臨時檔案
P78 time包
time.Time代表時間類型
時間戳是從1970年1月1日8點,到目前的總毫秒數
擷取時間戳,nano納秒
時間戳轉換成時間格式
時間間隔
時間操作+
明天的時間
時間就一秒鐘 給一個值
go的時間 格式化模闆是它的誕生時間 ,2006年1月2日15點04分,也就是 2006 1 2 3 4
轉換成字元串類型的時間,格式化
![zhuanzhuan![](https://img-blog.csdnimg.cn/76be4b8dc3024fccb2637f1f5c027f30.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBANDhONkU=,size_20,color_FFFFFF,t_70,g_se,x_16)
想要格式是2006/01/02 11:11:11
加上上午下午
加上毫秒
字元串類型轉換成時間戳
P79 time包補充
但凡調用其他包裡的東西,首字母都需要大寫,小寫調用不到
相差3600多個小時
可以試試UTC時間
減的是一個時間對象,傳回值是個 時間間隔,
指定時區
sleep,函數名(參數)沒有傳回值,參數是一個時間間隔的類型
**duration是一個基于int64的類型,定義了兩個常量,隻能在time包裡使用,需要判斷傳進來的參數是否符合要求,最大值最小值
**
這樣指派了傳進去就不比對了,類型不能轉換
需要顯示轉換類型
P80 日志庫需求分析
先看一下時區的問題,預設是擷取的本地的時間
明天的目前時間,按照東八區的時區和格式去解析一個字元串的時間。time.loadlocation根據字元串加載時區
按照指定時區解析時間parseinlocation,這樣就獲得了正确的東八區相減
P81 日志庫簡單實作
go語言的日志可以相對比較簡單
列印的時候會在前面加預設的時間戳
打開一個檔案,把日志輸出到檔案
日志庫的需求:
1支援往不同的地方輸出日志
2日志級别:debug,info,warning,error,fatal嚴重錯誤
3.日志支援開關
4.日志要有基本格式,時間,行号,檔案名,級别,日志資訊
5.日志檔案要切割
需要自己寫的程式調用自己寫的日志庫
日志庫開發,fprint是往檔案裡去寫
大概的架子
寫一個for循環調用
這些隻是最簡單的實作,離需求還差點
添加時間格式,并換行
再把日志級别加上去
日志開關,比如開發的時候什麼級别都可以輸出 ,上線之後隻有INFO級别輸出
基于内置的int16類型造了一個自己的類型level。iota第一個是0,每一行加1
需要實作一個方法,獲得字元串的級别,解析成内置類型的級别,parseloglevel
如果傳的類型什麼都不是,可以傳回一個unknown,錯誤
error.mew造一個新的錯誤
errors
使用者傳進來字元串的時候,需要解析。
構造一個logger對象,裡面有一個日志級别
如果上線就判斷隻輸出info級别的日志
每個函數都進行調用
如果是debug級别,相當于其他任何級别都可以輸出,是以是>=
P82 runtime.caller
可以添加一個行号,runtime是一個進行時,go自帶gc,caller,傳一個int參數,就可以拿到一個目前程式的隔了對應多少層,如果ok是true就可以拿到,如果是false,就拿不到。pc可以拿到函數的一些資訊,file是目前執行的哪個檔案,line是第幾行
main函數直接調用,是以直接傳入0.
main函數是程式的入口函數,需要傳其他數了,預設就是0
調用檔案的全部路徑。行數11
假如把這段代碼封裝到函數裡,在main函數裡調用,就隔了一層,列印的行号一定是執行runtime.caller的行号
想要擷取21行,這一行調用,就等于再往上找一層,就是21行
那麼再往上調用,再找一層就是25行了
拿到函數名,pc
拿到最終的f函數,寫個0即可
這樣就拿到f1
拿到檔案名
在外部進行調用
在記錄日志的地方進行調用
但是一個個 添加太麻煩,可以寫到一個log函數裡
再寫一個把日志級别進行轉換的函數getLogString
現在調用就有行号了
函數名 可以做一下分割
P83 記錄日志時支援格式化輸出
導入自己開發的包并進行調用
誰調用就記錄這個是誰調用的資訊
可以加一個格式參數,後面可以傳任何類型的參數等于是傳的資訊,和a是一個格式化的關系
可以往裡面傳字元串的格式化,可以傳任意格式的進去
P84 實作往檔案裡記錄日志
改個名字,區分一下
把日志存到檔案裡
newfiledlogger構造函數
把級别複制過來
可以加個參數,輸出的地方不同
都替換一下
這樣判斷就可以移到一個函數裡了,直接列印就行
這樣就更簡單了
檔案版的enable
但是肯定要一開始打開檔案就初始化好
按照檔案路徑和檔案名将檔案打開,寫日志都是追加,沒有就建立,這樣傳回一個檔案對象。
如果打開檔案失敗了就記錄一下。
日志檔案打不開就沒必要往下走了,還有一個專門輸出error日志的檔案
關閉檔案
往檔案裡去記錄
如果要記錄的日志等級大于等于error,還要在error日志檔案中再記錄一份
傳入參數
現在就有日志了
P85 日志檔案切割
可以按檔案大小切割,和按日期切割
判斷傳入的檔案是否是err,傳回os.file結構體的指針
原始包裡提供的時一個接口類型,裡面有一些方法,傳回值
擷取檔案對象的詳細資訊
上面的代碼移到之前的代碼裡,擷取傳進來的檔案大小,目前檔案大小大于等于日志檔案最大值就傳回true
在下面調用checksize。
進行日志切割
1.關閉目前日志檔案
2.備份一下 rename
3.打開一個新的日志檔案
4.将打開的新日志檔案對象指派給f.fileobj
重命名後,打開一個新的日志檔案,往裡面繼續寫日志
下面記錄錯誤日志的就也需要,把切割的代碼部分抽出去變成一個函數
這裡其實可以列印檔案名
還需要判斷切的時info日志還是err日志
傳回增加一個nil,split還需要接收對象
傳回的錯誤檔案對象
P86 日志庫補充
把原來的日志檔案先删除
報錯是因為檔案關閉了,就代表拿不到檔案資訊,
關閉檔案放到下面
備份
initfile的作用是建立檔案執行個體的時候,需要做一個初始化
寫的這些方法的作用
檔案日志結構體
console和記錄檔案的都需要實作日志界别,也就是可以定義interface接口
定義接口後,可以定義一個日志執行個體,在main包裡的任何地方去使用,或者其他包裡去使用。
定義一個構造函數
兩個都可以指派
也可以包裝起來,傳不同參數時候,可以進行switch
上面就是申明一個全局的接口變量
P87 反射及附加題需求
之前寫的類型,在go語言執行的時候就已經知道了是什麼類型,反射隻有執行到指定的行才知道是什麼類型
反射可以動态擷取
這樣是可以傳進去的,但是執行會報錯
任何接口值都是由一個具體類型和具體類型的值兩部分組成
也就是動态類型和動态類型的值
這樣就能拿到類型
類型分為了type和kind,kind對應底層造的類型
這樣就列印出來main.cat
類型,種類kind結構體
可以基于内置的類型造一個自己的類型
valueof傳回一個reflect.value的類型,其中包含原始值資訊,和原始值之間可以互相轉換。
這裡取到接口傳過來的變量,如果種類滿足int64,就轉換成int64;如果是float32就轉成float32
複制到這裡進行測試
下面拿到的是值的類型
通過反射設定變量的值,上面是讀變量的值,go語言的函數傳值永遠是拷貝,但凡修改值的時候,一定要return。
想要修改這個100,但是提示需要傳一個指針
傳一個指針,但是沒有修改成功,函數還需要修改
在函數裡這樣使用也就獲得了位址
這樣就直接修改了
isnil判斷特定的值是否未null,特有的值必須是通道,函數,接口,指針,映射,切片
結構體字段在反射裡也有類型structfield
學生結構體有名字和分數
可以傳回結構體字段數目
增加多個值,測試下面擷取
現在就擷取到了
反射有好處,有壞處。
好處:讓代碼更加靈活。
壞處:犧牲了一些代碼的性能
建立一個ini檔案
造一個結構體
把檔案裡的值拿出來,這是需要實作的
可以加上ini解析