類型推斷是一種編程語言在編譯期自動解釋表達式類型的能力。
1.Go語言的類型推斷可以帶來哪些好處?
在寫代碼時,我們通過使用Go語言的類型推斷會節省敲擊次數,而節省下來的鍵盤敲擊次數幾乎可以忽略不記。但它真正的好處,往往會體現在我們寫代碼之后的那些事情上,比如代碼重構。
我們依然通過調用一個函數在聲明name變量的同時為它賦值,但是這個函數不是flag.String,而是由我們自己定義的某個函數,比如叫getTheFlag。
package main
import ("flag""fmt"
)
func main() {var name = getTheFlag()flag.Parse()fmt.Printf("Hello, %v!\n", *name)
}
func getTheFlag() *string {return flag.String("name", "everyone", "The greeting object.")
}
我們可以用getTheFlag函數包裹(或者說包裝)那個對flag.String函數的調用,并把
其結果直接作為getTheFlag函數的結果,結果的類型是*string。
這樣一來,var name =右邊的表達式,可以變為針對getTheFlag函數的調用表達式
了。這實際上是對“聲明并賦值name變量的那行代碼”的重構
。
我們通常把不改變某個程序與外界的任何交互方式和規則,而只改變其內部實現”的代碼修改方式,叫做對該程序的重構。重構的對象可以是一行代碼、一個函數、一個功能模塊,甚至一個軟件系統。
你會發現,你可以隨意改變getTheFlag函數的內部實現,及其返回結果的類型,而不用修改main函數中的任何代碼。
這個命令源碼文件依然可以通過編譯,并且構建和運行也都不會有問題。也許你能感覺得到,這是一個關于程序靈活性的質變。
我們不顯式地指定變量name的類型,使得它可以被賦予任何類型的值。也就是說,變量name的類型可以在其初始化時,由其他程序動態地確定。
在你改變getTheFlag函數的結果類型之后,Go 語言的編譯器會在你再次構建該程序的時候,自動地更新變量name的類型。
Go 語言是靜態類型的,所以一旦在初始化變量時確定了它的類型,之后就不可能再改變。這就避免了在后面維護程序時的一些問題。另外,請記住,這種類型的確定是在編譯期完成的,因此不會對程序的運行效率產生任何影響。
Go語言的類型推斷可以帶來哪些好處?
回答:Go 語言的類型推斷可以明顯提升程序的靈活性,使得代碼重構變得更加容易,同時又不會給代碼的維護帶來額外負擔(實際上,它恰恰可以避免散彈式的代碼修改),更不會損失程序的運行效率。
2.變量的重聲明是什么意思?
涉及到短變量聲明。通過使用它,我們可以對同一個代碼塊中的變量進行重聲明。
在 Go 語言中,代碼塊一般就是一
個由花括號括起來的區域,里面可以包含表達式和語句。Go 語言本身以及我
們編寫的代碼共同形成了一個非常大的代碼塊,也叫全域代碼塊。
這主要體現在,只要是公開的全局變量,都可以被任何代碼所使用。相對小
一些的代碼塊是代碼包,一個代碼包可以包含許多子代碼包,所以這樣的代
碼塊也可以很大。接下來,每個源碼文件也都是一個代碼塊,每個函數也是一個代碼塊,每個
if語句、for語句、switch語句和select語句都是一個代碼塊。甚至,
switch或select語句中的case子句也都是獨立的代碼塊。
走個極端,我就在main函數中寫一對緊挨著的花括號算不算一個代碼塊?當
然也算,這甚至還有個名詞,叫“空代碼塊”。
變量重聲明的前提條件:
- 由于變量的類型在其初始化時就已經確定了,所以對它再次聲明時賦予的類型必須與其
原本的類型相同,否則會產生編譯錯誤。 - 變量的重聲明只可能發生在某一個代碼塊中。如果與當前的變量重名的是外層代碼塊中
的變量,那么就是另外一種含義了。 - 變量的重聲明只有在使用短變量聲明時才會發生,否則也無法通過編譯。如果要在此處
聲明全新的變量,那么就應該使用包含關鍵字var的聲明語句,但是這時就不能與同一個
代碼塊中的任何變量有重名了 。 - 被“聲明并賦值”的變量必須是多個,并且其中至少有一個是新的變量。這時我們才可
以說對其中的舊變量進行了重聲明。
這樣來看,變量重聲明其實算是一個語法糖(或者叫便利措施)。它允許我們在使用短變量
聲明時不用理會被賦值的多個變量中是否包含舊變量。可以想象,如果不這樣會多寫不少代
碼。
var err error
n, err := io.WriteString(os.Stdout, "Hello, everyone!\n")
我使用短變量聲明對新變量n和舊變量err進行了“聲明并賦值”,這時也是對后者的重聲明。
文章來自郝林老師的《Go語言36講》