Golang简介
??命令式语言
??静态类型
??语法标记类似于C(但括号较少且没有分号),结构类似Oberon-2
??编译为本机代码(没有JVM)
??没有类,但有带有方法的结构
??接口
??没有实现继承。不过有type嵌入。
??函数是一等公民
??函数可以返回多个值
??支持闭包
??指针,但没有指针算术
??内置并发原语:Goroutines和Channels
基本语法
你好,世界
文件hello.go:
package?main
import?"fmt"
func?main()?{
fmt.Println("Hello?Go")
}
$?go?run?hello.go运算符算术运算符
比较运算符
逻辑运算符
其他
声明
类型在标识符之后!
var?foo?int?//?declaration?without?initialization
var?foo?int?=?42?//?declaration?with?initialization
var?foo,?bar?int?=?42,?1302?//?declare?and?init?multiple?vars?at?once
var?foo?=?42?//?type?omitted,?will?be?inferred
foo?:=?42?//?shorthand,?only?in?func?bodies,?omit?var?keyword,?type?is?always?implicit
const?constant?=?"This?is?a?constant"
//?iota?can?be?used?for?incrementing?numbers,?starting?from?0
const?(
_?=?iota
a
b
c?=?1?
d
)
fmt.Println(a,?b)?//?1?2?(0?is?skipped)
fmt.Println(c,?d)?//?8?16?(2^3,?2^4)函数
//?a?simple?function
func?functionName()?{}
//?function?with?parameters?(again,?types?go?after?identifiers)
func?functionName(param1?string,?param2?int)?{}
//?multiple?parameters?of?the?same?type
func?functionName(param1,?param2?int)?{}
//?return?type?declaration
func?functionName()?int?{
return?42
}
//?Can?return?multiple?values?at?once
func?returnMulti()?(int,?string)?{
return?42,?"foobar"
}
var?x,?str?=?returnMulti()
//?Return?multiple?named?results?simply?by?return
func?returnMulti2()?(n?int,?s?string)?{
n?=?42
s?=?"foobar"
//?n?and?s?will?be?returned
return
}
var?x,?str?=?returnMulti2()函数作为值和闭包
func?main()?{
//?assign?a?function?to?a?name
add?:=?func(a,?b?int)?int?{
return?a?+?b
}
//?use?the?name?to?call?the?function
fmt.Println(add(3,?4))
}
//?Closures,?lexically?scoped:?Functions?can?access?values?that?were
//?in?scope?when?defining?the?function
func?scope()?func()?int{
outer_var?:=?2
foo?:=?func()?int?{?return?outer_var}
return?foo
}
func?another_scope()?func()?int{
//?won't?compile?because?outer_var?and?foo?not?defined?in?this?scope
outer_var?=?444
return?foo
}
//?Closures
func?outer()?(func()?int,?int)?{
outer_var?:=?2
inner?:=?func()?int?{
outer_var?+=?99?//?outer_var?from?outer?scope?is?mutated.
return?outer_var
}
inner()
return?inner,?outer_var?//?return?inner?func?and?mutated?outer_var?101
}可变参数函数
func?main()?{
fmt.Println(adder(1,?2,?3))??//?6
fmt.Println(adder(9,?9))?//?18
nums?:=?[]int{10,?20,?30}
fmt.Println(adder(nums...))?//?60
}
//?By?using?...?before?the?type?name?of?the?last?parameter?you?can?indicate?that?it?takes?zero?or?more?of?those?parameters.
//?The?function?is?invoked?like?any?other?function?except?we?can?pass?as?many?arguments?as?we?want.
func?adder(args?...int)?int?{
total?:=?0
for?_,?v?:=?range?args?{?//?Iterates?over?the?arguments?whatever?the?number.
total?+=?v
}
return?total
}内置类型
bool
string
int??int8??int16??int32??int64
uint?uint8?uint16?uint32?uint64?uintptr
byte?//?alias?for?uint8
rune?//?alias?for?int32?~=?a?character?(Unicode?code?point)?-?very?Viking
float32?float64
complex64?complex128
所有Go的预声明标识符都定义在builtin包中。
类型转换
var?i?int?=?42
var?f?float64?=?float64(i)
var?u?uint?=?uint(f)
//?alternative?syntax
i?:=?42
f?:=?float64(i)
u?:=?uint(f)包
??在每个源文件的顶部声明包
??可执行文件位于main包中
??约定:包的名称等于导入路径的最后一个部分(导入路径math/rand=> 包rand)
??大写标识符:导出的(可以从其他包中访问)
??小写标识符:私有的(不能从其他包中访问)
控制结构
判断
func?main()?{
//?Basic?one
if?x?>?10?{
return?x
}?else?if?x?==?10?{
return?10
}?else?{
return?-x
}
//?You?can?put?one?statement?before?the?condition
if?a?:=?b?+?c;?a?
return?a
}?else?{
return?a?-?42
}
//?Type?assertion?inside?if
var?val?interface{}?=?"foo"
if?str,?ok?:=?val.(string);?ok?{
fmt.Println(str)
}
}循环
//?There's?only?`for`,?no?`while`,?no?`until`
for?i?:=?1;?i?
}
for?;?i?
}
for?i?
}
for?{?//?you?can?omit?the?condition?~?while?(true)
}
//?use?break/continue?on?current?loop
//?use?break/continue?with?label?on?outer?loop
here:
for?i?:=?0;?i?
for?j?:=?i?+?1;?j?
if?i?==?0?{
continue?here
}
fmt.Println(j)
if?j?==?2?{
break
}
}
}
there:
for?i?:=?0;?i?
for?j?:=?i?+?1;?j?
if?j?==?1?{
continue
}
fmt.Println(j)
if?j?==?2?{
break?there
}
}
}条件
//?switch?statement
switch?operatingSystem?{
case?"darwin":
fmt.Println("Mac?OS?Hipster")
//?cases?break?automatically,?no?fallthrough?by?default
case?"linux":
fmt.Println("Linux?Geek")
default:
//?Windows,?BSD,?...
fmt.Println("Other")
}
//?as?with?for?and?if,?you?can?have?an?assignment?statement?before?the?switch?value
switch?os?:=?runtime.GOOS;?os?{
case?"darwin":?...
}
//?you?can?also?make?comparisons?in?switch?cases
number?:=?42
switch?{
case?number?
fmt.Println("Smaller")
case?number?==?42:
fmt.Println("Equal")
case?number?>?42:
fmt.Println("Greater")
}
//?cases?can?be?presented?in?comma-separated?lists
var?char?byte?=?'?'
switch?char?{
case?'?',?'?',?'&',?'=',?'#',?'+',?'%':
fmt.Println("Should?escape")
}数组, 切片, 遍历数组
var?a?[10]int?//?declare?an?int?array?with?length?10.?Array?length?is?part?of?the?type!
a[3]?=?42?????//?set?elements
i?:=?a[3]?????//?read?elements
//?declare?and?initialize
var?a?=?[2]int{1,?2}
a?:=?[2]int{1,?2}?//shorthand
a?:=?[...]int{1,?2}?//?elipsis?->?Compiler?figures?out?array?length切片
var?a?[]int??????????????????????????????//?declare?a?slice?-?similar?to?an?array,?but?length?is?unspecified
var?a?=?[]int?{1,?2,?3,?4}???????????????//?declare?and?initialize?a?slice?(backed?by?the?array?given?implicitly)
a?:=?[]int{1,?2,?3,?4}???????????????????//?shorthand
chars?:=?[]string{0:"a",?2:"c",?1:?"b"}??//?["a",?"b",?"c"]
var?b?=?a[lo:hi]?//?creates?a?slice?(view?of?the?array)?from?index?lo?to?hi-1
var?b?=?a[1:4]??//?slice?from?index?1?to?3
var?b?=?a[:3]??//?missing?low?index?implies?0
var?b?=?a[3:]??//?missing?high?index?implies?len(a)
a?=??append(a,17,3)?//?append?items?to?slice?a
c?:=?append(a,b...)?//?concatenate?slices?a?and?b
//?create?a?slice?with?make
a?=?make([]byte,?5,?5)?//?first?arg?length,?second?capacity
a?=?make([]byte,?5)?//?capacity?is?optional
//?create?a?slice?from?an?array
x?:=?[3]string{"Лайка",?"Белка",?"Стрелка"}
s?:=?x[:]?//?a?slice?referencing?the?storage?of?x数组和切片的操作
len(a)返回数组/切片的长度。这是一个内置函数,而不是数组的属性/方法。
//?loop?over?an?array/a?slice
for?i,?e?:=?range?a?{
//?i?is?the?index,?e?the?element
}
//?if?you?only?need?e:
for?_,?e?:=?range?a?{
//?e?is?the?element
}
//?...and?if?you?only?need?the?index
for?i?:=?range?a?{
}
//?In?Go?pre-1.4,?you'll?get?a?compiler?error?if?you're?not?using?i?and?e.
//?Go?1.4?introduced?a?variable-free?form,?so?that?you?can?do?this
for?range?time.Tick(time.Second)?{
//?do?it?once?a?sec
}哈希表
m?:=?make(map[string]int)
m["key"]?=?42
fmt.Println(m["key"])
delete(m,?"key")
elem,?ok?:=?m["key"]?//?test?if?key?"key"?is?present?and?retrieve?it,?if?so
//?map?literal
var?m?=?map[string]Vertex{
"Bell?Labs":?{40.68433,?-74.39967},
"Google":????{37.42202,?-122.08408},
}
//?iterate?over?map?content
for?key,?value?:=?range?m?{
}结构体
Go中没有类,只有结构体。结构体可以拥有方法。
//?A?struct?is?a?type.?It's?also?a?collection?of?fields
//?Declaration
type?Vertex?struct?{
X,?Y?float64
}
//?Creating
var?v?=?Vertex{1,?2}
var?v?=?Vertex{X:?1,?Y:?2}?//?Creates?a?struct?by?defining?values?with?keys
var?v?=?[]Vertex{{1,2},{5,2},{5,5}}?//?Initialize?a?slice?of?structs
//?Accessing?members
v.X?=?4
//?You?can?declare?methods?on?structs.?The?struct?you?want?to?declare?the
//?method?on?(the?receiving?type)?comes?between?the?the?func?keyword?and
//?the?method?name.?The?struct?is?copied?on?each?method?call(!)
func?(v?Vertex)?Abs()?float64?{
return?math.Sqrt(v.X*v.X?+?v.Y*v.Y)
}
//?Call?method
v.Abs()
//?For?mutating?methods,?you?need?to?use?a?pointer?(see?below)?to?the?Struct
//?as?the?type.?With?this,?the?struct?value?is?not?copied?for?the?method?call.
func?(v?*Vertex)?add(n?float64)?{
v.X?+=?n
v.Y?+=?n
}
匿名结构体:比使用map[string]interface{}更经济和更安全。
point?:=?struct?{
X,?Y?int
}{1,?2}指针
p?:=?Vertex{1,?2}??//?p?is?a?Vertex
q?:=?&p????????????//?q?is?a?pointer?to?a?Vertex
r?:=?&Vertex{1,?2}?//?r?is?also?a?pointer?to?a?Vertex
//?The?type?of?a?pointer?to?a?Vertex?is?*Vertex
var?s?*Vertex?=?new(Vertex)?//?new?creates?a?pointer?to?a?new?struct?instance接口
//?interface?declaration
type?Awesomizer?interface?{
Awesomize()?string
}
//?types?do?*not*?declare?to?implement?interfaces
type?Foo?struct?{}
//?instead,?types?implicitly?satisfy?an?interface?if?they?implement?all?required?methods
func?(foo?Foo)?Awesomize()?string?{
return?"Awesome!"
}嵌入
Go中没有子类化。相反,有接口和结构体嵌入。
//?ReadWriter?implementations?must?satisfy?both?Reader?and?Writer
type?ReadWriter?interface?{
Reader
Writer
}
//?Server?exposes?all?the?methods?that?Logger?has
type?Server?struct?{
Host?string
Port?int
*log.Logger
}
//?initialize?the?embedded?type?the?usual?way
server?:=?&Server{"localhost",?80,?log.New(...)}
//?methods?implemented?on?the?embedded?struct?are?passed?through
server.Log(...)?//?calls?server.Logger.Log(...)
//?the?field?name?of?the?embedded?type?is?its?type?name?(in?this?case?Logger)
var?logger?*log.Logger?=?server.Logger错误
Go中没有异常处理。相反,可能产生错误的函数只是声明了一个额外的返回值,类型为error。这是error接口:
//?The?error?built-in?interface?type?is?the?conventional?interface?for?representing?an?error?condition,
//?with?the?nil?value?representing?no?error.
type?error?interface?{
Error()?string
}
这是一个示例:
func?sqrt(x?float64)?(float64,?error)?{
if?x?
return?0,?errors.New("negative?value")
}
return?math.Sqrt(x),?nil
}
func?main()?{
val,?err?:=?sqrt(-1)
if?err?!=?nil?{
//?handle?error
fmt.Println(err)?//?negative?value
return
}
//?All?is?good,?use?`val`.
fmt.Println(val)
}并发协程
Goroutines是轻量级线程(由Go管理,而不是操作系统线程)。go f(a, b)启动一个新的goroutine来运行f(假设f是一个函数)。
//?just?a?function?(which?can?be?later?started?as?a?goroutine)
func?doStuff(s?string)?{
}
func?main()?{
//?using?a?named?function?in?a?goroutine
go?doStuff("foobar")
//?using?an?anonymous?inner?function?in?a?goroutine
go?func?(x?int)?{
//?function?body?goes?here
}(42)
}通道
ch?:=?make(chan?int)?//?create?a?channel?of?type?int
ch?
v?:=?
//?Non-buffered?channels?block.?Read?blocks?when?no?value?is?available,?write?blocks?until?there?is?a?read.
//?Create?a?buffered?channel.?Writing?to?a?buffered?channels?does?not?block?if?less?than??unread?values?have?been?written.
ch?:=?make(chan?int,?100)
close(ch)?//?closes?the?channel?(only?sender?should?close)
//?read?from?channel?and?test?if?it?has?been?closed
v,?ok?:=?
//?if?ok?is?false,?channel?has?been?closed
//?Read?from?channel?until?it?is?closed
for?i?:=?range?ch?{
fmt.Println(i)
}
//?select?blocks?on?multiple?channel?operations,?if?one?unblocks,?the?corresponding?case?is?executed
func?doStuff(channelOut,?channelIn?chan?int)?{
select?{
case?channelOut?
fmt.Println("We?could?write?to?channelOut!")
case?x?:=?
fmt.Println("We?could?read?from?channelIn")
case?
fmt.Println("timeout")
}
}通道原理
??向空通道发送会永远阻塞
var?c?chan?string
c?
//?fatal?error:?all?goroutines?are?asleep?-?deadlock!
??从空通道接收会永远阻塞。
var?c?chan?string
fmt.Println(
//?fatal?error:?all?goroutines?are?asleep?-?deadlock!
??向已关闭的通道发送会引发恐慌。
var?c?=?make(chan?string,?1)
c?
close(c)
c?
//?panic:?send?on?closed?channel
??从已关闭的通道接收会立即返回零值。
var?c?=?make(chan?int,?2)
c?
c?
close(c)
for?i?:=?0;?i?
fmt.Printf("%d?",?
}
//?1?2?0
打印
fmt.Println("Hello,?你好,???????,?Привет,????")?//?basic?print,?plus?newline
p?:=?struct?{?X,?Y?int?}{?17,?2?}
fmt.Println(?"My?point:",?p,?"x?coord=",?p.X?)?//?print?structs,?ints,?etc
s?:=?fmt.Sprintln(?"My?point:",?p,?"x?coord=",?p.X?)?//?print?to?string?variable
fmt.Printf("%d?hex:%x?bin:%b?fp:%f?sci:%e",17,17,17,17.0,17.0)?//?c-ish?format
s2?:=?fmt.Sprintf(?"%d?%f",?17,?17.0?)?//?formatted?print?to?string?variable
hellomsg?:=?`
"Hello"?in?Chinese?is?你好?('Ni?Hao')
"Hello"?in?Hindi?is????????('Namaste')
`?//?multi-line?string?literal,?using?back-tick?at?beginning?and?end反射类型切换
类型切换类似于常规的switch语句,但类型切换中的情况指定要与给定接口值持有的值的类型进行比较的类型,而不是值。
func?do(i?interface{})?{
switch?v?:=?i.(type)?{
case?int:
fmt.Printf("Twice?%v?is?%v\n",?v,?v*2)
case?string:
fmt.Printf("%q?is?%v?bytes?long\n",?v,?len(v))
default:
fmt.Printf("I?don't?know?about?type?%T!\n",?v)
}
}
func?main()?{
do(21)
do("hello")
do(true)
}片段文件嵌入
Go程序可以使用"embed"包嵌入静态文件,如下所示:
package?main
import?(
"embed"
"log"
"net/http"
)
//?content?holds?the?static?content?(2?files)?for?the?web?server.
//go:embed?a.txt?b.txt
var?content?embed.FS
func?main()?{
http.Handle("/",?http.FileServer(http.FS(content)))
log.Fatal(http.ListenAndServe(":8080",?nil))
}
完整的Playground示例
HTTP服务器
package?main
import?(
"fmt"
"net/http"
)
//?define?a?type?for?the?response
type?Hello?struct{}
//?let?that?type?implement?the?ServeHTTP?method?(defined?in?interface?http.Handler)
func?(h?Hello)?ServeHTTP(w?http.ResponseWriter,?r?*http.Request)?{
fmt.Fprint(w,?"Hello!")
}
func?main()?{
var?h?Hello
http.ListenAndServe("localhost:4000",?h)
}
//?Here's?the?method?signature?of?http.ServeHTTP:
//?type?Handler?interface?{
//?????ServeHTTP(w?http.ResponseWriter,?r?*http.Request)
//?}
领取专属 10元无门槛券
私享最新 技术干货