首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Golang语法、技巧和窍门

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)

//?}

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OLTzEfr0uyTRoIS148_6eutg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券
http://www.vxiaotou.com