参数传递:
实质上只有值传递
内存有状态的时候要把参数封装成指针,例如:内存有多个状态,多块内存等
定义变量:
名称在前,类型在后
加var可以不赋值,但是后面赋值用=
不加var需用 := 进行赋值
没用到的变量用 _ 代替
类型转换:
[]byte(s) //string转字符数组
float64(5)
无enum:
用const( )代替
if:
条件没有括号
两个大括号嵌套的条件可以用 ;分隔,省掉两个大括号
没有while:
for代替
switch:
没有break,也可以switch多个条件
报错:
panic(…) 打印并停止
fmt.Errorf(“Error:%s”,) 打印
fmt.Println(“Error:”,err)
一行一行读:
file,error := os.open(…)
scanner := NewScanner(file)
函数式编程:
通过函数式编程改写switch case:
op是一个函数,传两个int参数,返回一个int
func apply(op func(int,int) int,a ,b int) int {
通过反射拿op的名字:
runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name()
return op(a,b)
}
函数编程简写:
使用匿名函数直接定义在函数肚子里:
fmt.Println(apply(
func(a int,b int) int{
return int math.Pow(float64(a),float64(b))
},3,4))
可变参数列表:
像数组一样使用
func sum(number,…int) int {
s := 0
for i := range numbers{
s += numbers[i]
}
return s
}
sum(1,2,3,4,5)
指针:
go语言中指针不能做加法
var a int = 2
var pa *int = &a
*pa = 3
数组:
var arr1 [5]int
var group[3][4]int
arr2 := [3]{1,3,5}
arr3 := […]int{1,2,3,4}
fmt.Println(arr1,group,arr2,arr3)
遍历数组下标和元素:
for i,v := range arr3{ fmt.Println(i,v)}
数组做参数:
参数一般不用数组,而是用切片
数组是值类型,需要给定数组大小,做参数会拷贝。没有给数组大小的是切片
func printArray(arr [5]int){} //传值
func printArray(arr *[5]int){} //传指针
Slice(切片):
切片就是一个视图
arr := […]int{0,1,2,3,4,5,6,7}
s : = arr[2:6] //s的值为[2 3 4 5]
s : = arr[:6] //s的值为[0 1 2 3 4 5]
s : = arr[2:] //s的值为[2 3 4 5 6 7]
s : = arr[:] //s的值为[0 1 2 3 4 5 6 7]
容量cap(arr)是向后扩展的上限,即append的数量超出arr的容量后,系统会重新分配数组,所以切片必须接受值
s1 := p[]int{2,4,6,8}
s2 := make([]int,16) //16个空间,cap为16
s3 := make([]int,16,32) //16个空间,cap为32
s2 = append(s2[:3],s2[4:]...] //删除第四个元素
s2 = s2[len(s2)-1] //删除尾部元素
map:
是一个hashmap,key是无序的;未初始化也可以用,是一个zero value
m := map[string]string{“name”:“a”,“course”:“b”} //map[key]value
m2 := make(map[string]int) //m2 == empty map
var m3 map[string]int //m3 = nil
courseName := m[“course”] //取值m[key]
courseName ,ok := m[“course”] //ok返回value是否存在
delete(m,“course”) //删除
遍历使用range,不保证顺序;需要排序需要放入Slice中去
除slice,map,function外的内建类型可作为key
遍历字符串:
for _, b := range []byte(s){
fmt.Printf("%x",b)} //十六进制
for i, ch := range s{
fmt.Printf("(%d %x)",i,ch)}
//UTF-8转uni code
bytes := []byte(s) //获得所有字节
for len(bytes) > 0{
ch, size := utf8.DecodeRune(bytes)
bytes = bytes[size:]
fmt.Printf("%c", ch)
}
//string转[]rune变成一个规整数组,不需要转换UTF-8来解决中文字符问题
for i, ch := range []rune(s){ fmt.Printf("(%d %x)",i,ch) }
//获取字符数
utf8.RuneCountInString
//对字符串做操作的函数,在strings包
strings.
//其他字符串操作
Fields,Split,Join
Contains,index
ToLower,ToUpper
Tim, TrimRight, TrimLeft
对象调用:
不管是对象还是指针,一律用.来访问
工厂函数:
func createNode(value int) *treeNode{
return &treeNode{value: value}}
参数传递写法:
//以下是同一个意思,但是调用方法不一样
func (node treeNode) print(){} //root.print()
func print(node treeNode){} //print(root)
//参数为传值,如果需要修改值应修改为(node *treeNode)
func (node *treeNode) setValue(value int){ node.value = value }
root treeNode
pRoot := &root
pRoot.setValue(200)
权限:
针对包(package)来说:一个目录只能有一个包, 函数、结构体等给别人用首字母需要大写
首字母大写代表public
首字母小写代表private
红线表示没权限,灰线表示名称不建议这么命名
类型扩充:
定义别名:
使用组合:
Queue:
实际是一个Slice
func (q *Queue) Push(v,int){ *q = append(*q,v) } //push
func (q *Queue) Pop() int{ //pop
head := (*q)[0]
*q = (*q)[1:]
return head
}
GOPATH环境变量:
存放了各种包
默认在~/go(nunix,linux), %USERPROFILE%\go(windows)
官方推荐:所有项目和第三方库都放在GOPATH下
也可以每个项目放在不同的GOPATH
查看命令:pwd ,echo $GOPATH,echo $PATH, cat ~/.bash_profile
go 命令:
go get -v //获取第三方库
gopm get -g -v -u //获取无法下载的包
go build //编译
go install //产生pkg文件盒可执行文件
go run //直接编译运行
./… //当前目录下所有文件
git 命令主要用于网上代码的下载
GOPATH下目录结构:
src //代码和各种包
pkg //编译的中间文件
bin //可执行文件
接口:
type Traversal interface{ Traverse() }
traversal := getTraversal()
traversal.Traverse()
duck typing(大黄鸭):
传统不是鸭子,无生命特征 //内部活动
duck typing 是鸭子,像鸭子 //外部行为
go 语言类似 duck typing //编译时绑定,非动态绑定
函数支持int类型:
type Queue []int
func (q *Queue) Push(v int){
*q = append(*q,v)}
func (q *Queue) Pop() int{
head : = (*q)[0]
*q = *q[1:]
return head}
接口函数支持任何类型:
type Queue []interface{}
func (q *Queue) Push(v interface{}){
*q = append(*q,v)}
func (q *Queue) Pop() interface{
head : = (*q)[0]
*q = *q[1:]
return head}
//如果要限定int类型
func (q *Queue) Push(v int){
*q = append(*q,v.(int))} //强制转换
func (q *Queue) Pop() int{
head : = (*q)[0]
*q = *q[1:]
return head.(int)} //强制转换
接口函数定义和使用:
–使用者定义接口,实现者实现接口;go中与传统C++、JAVA中由实现者定义接口不同
–downLoad是使用者,retriever是实现者
//实现Retriever接口
在包fake中添加一个retriever.go文件
package fake
type Retriever struct{
Contents string
}
不需要接口名称,只要实现GetUrl方法就认为实现了Retriever接口
func (r Retriever) Get(url string) string{
return r.Contents
}
//在main.go定义接口
type Retriever interface{
Get(url string) string
}
//调用接口的函数
func dowload(r Retriever) string{
return r.Get("http://www.google.com")
}
main函数中使用:
var r Retriever
r = my.Retriver{"this is a fake url"}
fmt.Printf("%T %v\n",r,r) //fake.Retriever {this is a fake url} 类型,值
fmt.Println(download(r))
v := r(type) //类型
v.Contents //值
fakeRetriever := r.(fake.Retriever) //类型
fakeRetriever.Contents //值
真实接口:
在包real中添加一个retriever.go文件
type Retriever struct{
UserAgent string
TimeOut time.Duration
}
func (r Retriever) Get(url string) string{
resp,err := http.Get(url)
if err != nill {
panic(err)
}
result,err := httputil.DumpResponse(resp,true)
resp.Body.Close()
if err != nill {
panic(err)
}
return string(result)
}
//在main函数中使用
fmt.Println(download(real.Retriever(){}))
接口函数使用规则:
值接收者直接以对象.调用
指针接收者需要在在对象前加&
接口组合:
在main中定义另外一个接口Poster:
type Poster interface{
Post(url string,form map[string]string) string }
func post(poster Poster){
poster.Post("http://www.baidu.com",
map[string]string{"name":"xingdongfang", "course":"golang"})
}
//组合接口
type RetrieverPoster interface{
Retriever
Poster
}
const url = "http://www.baidu.com"
func session(s RetrieverPoster ) string{
s.Post(url,map[string]string {"contents":"another fake url",})
return s.Get(url)
}
//在fake包的Retriever.go中实现接口函数Post
func (r Retriever) Post(url string,form map[string]string) string {
r.Contents = form["contents"]
return "ok"
}
//main函数中调用
fmt.Printf(session(Retriever)) //由于Post和Get是值接收者,故值不会改变,需要修改为指针接受者
常用系统接口:
Stringer //字符串处理
Reader,Writer //文件读写,底层文件读写相关的函数做成Reader或Writer
、"abd"、 //跨行字符串
函数式编程与闭包:
函数是一等公民: 参数,变量,返回值可以是返回值
高阶函数: 函数的参数是一个函数
闭包: 以下面adder()说明,函数体有局部变量v,有自由变量sum(不断连接组成一棵树)
//go语言不遵循正统函数式编程: 不能有状态(不可变性),只有常量和函数,只有一个参数
函数式编程实例:
//函数式编程,闭包概念
func adder() func(int) int{
sum := 0 //环境自由变量,会被改变
return func(v int) int{
sum += v
return sum
}
}
//改成正统函数式编程
type iAdder func(int) (int,iAdder) //递归定义
func adder2(base int) iAdder{
return func(v int) (int ,iAdder){
return base + v,adder2(base + v)
}
}