golang基础学习

来源:转载

刚找了个新工作,应公司的要求必须用go语言来开发服务器。特此将自己对于go语言的学习经历写出来,帮助那些正在golang学习路上挣扎的迷茫的小伙伴们。

本文只是讲解自己最基础的一个学习过程,从最基础的变量开始,到最后利用golang搭建一个简单的服务器项目的过程,肯定有不少的错误或瑕疵,千万别当做标准的文档去看,仅仅是自己的一个学习过程的总结。希望大家理解,也仅仅是自己对自己每周学习过程的一个总结,每周更新一次。带大家用代码学习golang,用开源项目学习整个项目的框架逻辑。抽象的东西最好用实例来理解

使用环境:ubuntu 14+go1.4+sublime 2(go插件gosublime)

遇到不会的函数---查看官方包文件 http://godoc.golangtc.com/pkg/

golang基础

变量,array/slice/map,struct/func/method/interface,channel

具体内容参考我的CSDN代码页

1.怎样让map[string][]string 根据key的值按顺序输出

const--type--array(创建,数组指针/指针数组,元素遍历,冒泡排序)slice(2种创建/append/copy)map(创建,值类型为map,交换键值顺序,range)函数(调用/参数的值传递和址传递,不定参/defer,匿名函数作为值,匿名函数()问题,错误处理)结构体(创建和使用赋值,值传递和址传递,嵌套结构)方法(为类型添加方法,面向对象和面向过程区别,求矩形面积和周长,修改对象的值接口赋值,)接口(冒泡排序,)并发(开启新线程,channel,close,select,)web应用----------------------------------------------------------------------------------------go基础25个内置关键字:package--import--type--struct--interface--const--func--var--if--elseswitch--case--default--for--range--goto--break--continue--return--mapgo--chan--select--defer--fallthrough内置函数:15个close--delete--len/cap--new--make--append--copy--print--printlnpannic--recover--3复数函数new(type) 用于各种类型的内存分配make(map/slice/channel) 用于这3中类型的内存分配var 声明 make初始化 都不需要赋值1.变量变量就是存储某种或者某些数据的存储器,对一块数据存储空间的命名,引用变量名来使用这块空间变量类型基础数据类型:整型:int/uint int8/uint8 int16/uint16 int32/uint32 int64/uint64浮点型: float32/float64布尔型:true false 1字节字节型:byte ===uint8 UTF-8字符串单个字节字符型:rune Unicode字符字符串:string []byte错误类型:error复合类型:指针:pointer *i数组:array [n]int [...]string切片:slice []int字典:map map[int]string通道:chanel chan int c<- -<c结构体:struct 接口:interface 函数:func(){}自定义类型 type2.常量 constants在编译时就已经确定的值后面声明的局部变量和前面的常量名相同,则会覆盖前面的常量值3.数组array(1)数组是一系列同一类型的数据的集合,在内存上地址是连续的,且长度在定义后无法修改(2)数组是值类型,所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作,在函数体重无法修改传入的数组的内容,因为操作的只是该数组的一个副本4.slice(1)看起来类似一个指向数组的指针,作为参数传递是不会产生拷贝,它的数据结构可以抽象为3个变量(指向原生数组的指针,len,cap)可以随时动态的扩充存放空间(2)基于数组和直接创建,5.map(1)map是一组键值对的未排序集合,有delete删除对应键的值(2)类似map[2][1]的返回值6.function(1)go语言的函数有 不定参数,多返回值,匿名函数和闭包,函数也是一种类型即是值类型又是引用类型,有匿名函数有无()的区别,有返回值的函数可以当做一个值赋值给对应的变量,没有返回值的函数不能使用赋值操作(2)函数的调用,包名.函数名 但是对应的函数名必须在包内是大字母开头,go语言中没有封装的概念,没有private和public。(3)go语言的函数可以像普通变量一样被传递或者使用,匿名函数即不需要定义函数名的一种实现方式,只需要关键字func(4)匿名函数就是一个闭包,闭包关键的是局部变量和全局变量闭包的价值在于 可以将函数存储到变量中作为参数传递给其他函数,而且能够被函数动态的创建和返回(5)错误处理go语言引入了一个关于错误处理的标准模式,定义了一个error接口类型,里面有一个Error()方法,一般将函数的最后一个返回值作为异常信息经典用法errors.New("error strings")自定义错误处理函数func A() error{} 即返回值为错误类型7.struct(类)(1)GO语言的结构体实现面向对象的功能,一般用&来初始化结构体,这样在后面对于结构的传递就是地址传递,不会产生拷贝。初始化类似于map,用: 也可以不用,但一定要有{},数组也是{}。值和指针都是可以直接用 . 来操作(2)嵌套结构的实现,类似于其他语言的继承,go语言的面向对象编程,有结构和方法,接口组成8.method(1)方法就是有接收者的匿名函数,可以为任何类型(除指针和接口)添加别名成为新类型然后为新定义的类型创建函数操作,即为类型添加方法(2)强制性的第一个参数receiver,即要有接收者,(3)method value和method expression9.interface(1)接口就是一个或多个方法签名的的集合,接口为定义,方法为实现因此接收者不能是接口或者指针,接口名字为方面名加上er要实现某个接口,只需要实现该接口要求的所有函数即可。(2)当要修改对象时,才必须用指针,不是必须的,不是go语言的约束有时对象很小(4字节),用指针传递并不划算(3)接口赋值,将对象实例赋值给接口。对象实例即声明对应类型的变量接口组合:ReadWriteer(4)Any类型,空接口interface{},任何实例对象都满足空接口,可以指向任何对象10.concurrency(1)高并发是go语言的特点,goroutine是官方实现的超级线程池占用4-5KB的栈内存,并发是由cpu切换时间片来实现同时运行,不是并行同一个程序中的goroutine共享同一个地址空间。一般通过睡眠的方式来编排线程之间的相互等待不方便,有管道(2)channel,go语言的一个构件,引用类型,基于make函数来分配通信模型是 消息机制即channel,不是共享内存的方式提供一种机制用于goroutine之间通过传递指定类型的值进行通信(3)默认的无缓冲管道,发送方会阻塞直到接收方从管道中接收了值,创建的有缓冲管道,发送方会阻塞直到发送的值被拷贝到缓冲区,如果缓冲已满,那么接收方在有值可以接收之前会一种阻塞(4)close 函数标志着不会在往某个管道发送值并且在之前发送的值都被接收后接收操作会返回一个类型零值,不会阻塞(5)select, 监听管道上接收的数据,替代原来的<-chan接收数据的方式(6)死锁。线程之间相互等待,其中任何一个都无法向前运行的情形当没有任何goroutine能够前往执行的情况发送时,go会提供详细的错误信息(7)互斥锁,数据竞争data race,避免它的唯一方式就是线程间同步访问所有的共享可变数据。处理并发数据访问的推荐方式是:使用管道从一个goroutine往下一个goroutine传递实际的数据对所有共享数据的访问,不管读写,仅当goroutine持有锁才能操作,(8)共享内存:不同进程间的内存是相互独立的,没办法直接操作对方内的数据内存映射机制,让不同进程的同一块地址空间映射到同一个虚拟内存区,11.搭建一个http(WEB)服务器(1)http.listenAndServer(":1234",nil)开始监听服务,表示本机所有ip地址的1234端口,提示页面没找到表示http服务已经开启,即第二个参数决定路径网页内容等(2)myServeHttp(w http.ResponseWrite,r *http.Request)注意,监听函数的第二个参数是Handle接口,里面实现了ServeHttp()方法,要写入监听函数的第二个参数里面,方法名一定要是这个,可以定义一个新类型,添加这个方法名,具体实现自己写,传参数时&a{}(3)http.ResponseWrite 字面意思即服务器给客户端的回应,并写出来用 io.WriteString(w,"要传递个客户端的内容")(4)* http.Request 字面意思即客户端给服务器的请求,如r.URL.String()即客户端的url地址(5)http.HandleFunc("/",myServeHttp)注册一个myServeHTTP函数给"/",但浏览器浏览"/"会自动调用myServeHTTP函数。注册路由,(6)通过服务器传送文件给客户端查看句柄,编辑句柄,保存句柄(7)html文档直接写在打印语句(数据)里面,传送给客户端。由html/template模板库创建html文件,执行对应句柄,并可以渲染模板,精简代码量访问不存在的页面的处理方式,返回对应的状态码。尽量添加错误处理方式。template.ParseFiles()经常调用很浪费资源,可以将所有要渲染的文件放在一个模板指针里(8)安全问题12.http协议(1)我们输入URL后,我们的浏览器给Web服务器发送了一个Request, Web服务器接到Request后进行处理,生成相应的Response,然后发送给浏览器, 浏览器解析Response中的HTML,这样我们就看到了网页(2)发送的一个url就是http requestURL详解基本格式如下schema://host[:port#]/path/.../[?query-string][#anchor]http://www.mywebsite.com/sj/test/test.aspx?name=sviergn&x=true#stuff(3)HTTP消息的结构先看Request 消息的结构, Request 消息分为3部分,第一部分叫Request line, 第二部分叫Request header, 第三部分是body。 header和body之间有个空行Response消息的结构, 和Request消息的结构基本一样。 同样也分为三部分,第一部分叫Response line, 第二部分叫Response header,第三部分是body. header和body之间也有个空行(4)r.header服务器和客户端的r.header是不一样的,结构都是 map[string][]string客户端:map[Content-Type:[text/plain;charset=utf-8],Date:[Fri,...],Content-Length:[25]]服务器:map[User-Agent:[go 1.1 package http],Referer:[http://..],Accept-Encoding:[g-zip]]自定义http header(5)Http get,post,soap协议都是在http上运行的1)get:请求参数是作为一个key/value对的序列(查询字符串)附加到URL上的 查询字符串的长度受到web浏览器和web服务器的限制(如IE最多支持2048个字符),不适合传输大型数据集同时,它很不安全2)post:请求参数是在http标题的一个不同部分(名为entity body)传输的,这一部分用来传输表单信息,因此必须将Content-type设置为:application/x-www-form-urlencoded。post设计用来支持web窗体上的用户字段,其参数也是作为key/value对传输服务器通过请求的指针里面 r.ParseForm()来获得客户端通过GET/POST方式传递的参数13.go工具go使用静态链接,所有标准类库的packages可以使用短名字,如:fmt。对于你自己的Packages,最好提供一个base path(基路径),这可以避免命名冲突,下面是我的命名原则happygo.codeplex.com/study/hellopackage main //command executable(命令行可执行程序)必须使用main作为package名字包名字(Package Name)一些规则:一个package(文件件)中的所有文件必须使用相同的名字。Go语言约定import path(导入路径)的最后一个元素是包名字。Executable Commands必须使用 package main。import(加载模块,即寻找对应的.go文件)标准库,相对路径,绝对路径,点操作,别名操作,_操作import "fmt" fmt是标准库,它是去goroot下加载改模块加载自己写的模块,默认是$GOPATH/srcimport "./model" 当前文件的同一目录的model子目录import "/project/model" 加载 $GOPATH/src/project/model_操作,表示对包的引用,而不是直接使用包里面的函数,只是调用了该包里面的init()函数,自己在新建自己的包也要定义相关的init函数程序初始化和执行都起始于main包,执行import,再对包级常量和变量初始化,再执行init()函数,最后执行下面的内容go语言编译与链接go build --在当前目录下生成一个bin文件,不是main包的文件什么都不会生成go install --自动生成bin pkg文件夹,在里面生成bin文件和.a文件。是针对包不用加文件名直接后面跟的是文件夹名称,有个main包,里面有其他的自己新建的包,导入格式为相对路径或者绝对路径且只有再 goinstall后,生成了.a文件,才能在调用包的时候成功的看到包内大写字母开头的函数,才能.处理,否则是看不到的链接是将link,将主程序与库合成一个可执行的程序。改变了某个包后,必须要重新编译,这是go语言的特点,但是编译快把自己写的包打包成.a格式 在src目录下运行,go install project/sort1 也可以直接去对应目录的对.go文件,直接go install,不加文件名自己写的包只有在go install 打包后才能用。也可以在main包中import对应的包,再去main.go下面直接go install并且只有main包的main函数才会生成bin文件,多次import同一个包,只会导入一次GO的引用是 一级包/二级包/包名 比如example/newmath测试是针对包,不用再写个main去执行对应的函数,直接在Testxx函数里面实现测试代码中,函数可以用如下方式命名:Test_T_M,其中T为类型名,M为方法名,这样容易区分,但这不是Go语言的强制要求。go test -run=Test_Add大环境搞明白了,语法就快了,再学习一下语法,然后开发个应用试试14.gitflag包对命令行参数的解析定义flags的2种方式var ip=flag.Int("flagname",1234,"help message")var flagvar int---初始化函数flag.IntVar(&amp,"flagVal",1324,"helpmessage")命令行参数使用形式的./hello --a "pa" -age=132 通过flag学标准库的制定方法flag.Args()----------返回的是一个 []string,是string数组flag.Arg(i)----------返回的是对应参数i的输入的参数,单个的stringflag.NArg()----------返回的是输入的参数的个数git add test.go---git commit -m "message"---git push name1 mastergit remote 查看当前配置有哪些远程仓库,默认为origin,添加 git remote add name1 http://github.com/jllei/basic或者是git://github.com/.. git branch 列出本地分支,-r/a,创建 git branch newbranch1 删除 git branch -d |-D branchname 删除远程分支 git branch -d -r branchname切换分支 git checkout branchname推送本地分支到远程分支 git push origin branchname合并分支 git checkout master --- git diff --- git merge b0702合并 --- 删除git branch -d b0702 master分支是非常稳定的,仅用来发布新版本,平时工作都在自己新建的分支 dev上,再建自己的分支,最后合并到dev上15.golang操作mysqlgo get github.com/go-sql-driver/mysql16.markov马尔科夫链算法生成任意文本一个链由一个前缀和后缀组成 模拟 map[string][]string前缀是一个字符串数组,处理后为: 加了空格的,拥有prefixlen个单词的字符串 "i am s" 长度为3后缀是一个单词,一个前缀可以有多个后缀,模拟为{"a","not"}前缀 []string{"i","am"} --- 映射键 "i am" 将字符串连同空格一起加入到其中生成映射键前缀类型 type Prefix []string ----并添加2个方法func (p *Prefix) str() string{} 将前缀作为字符串(映射键)返回,func (p *Prefix) Shift(word string){} 将前缀中移除第一个单词并追加上给定的单词 "i am" --"am not"链初始化函数 / 构造函数 func NewChain(prefixlen int) *Chain{}Chain结构体类型,包含了前缀到后缀的映射map[string][]string 和前缀长度prefixlen---添加2个方法 func(c *Chain)Build(r io.Reader){} 构建链,从Reader接口中读取文本,用缓存输入,这里是os.stdin,解析并储存func (c *Chain)Generate(n int)string{} 返回一个从Chain中生成的,最多有n个单词的字符串--------------------------------------------------------------------------------------------code--------------------------------------------------------------------------------------------code--------------------------------------------------------------------------------------------code------------------------------------------------------const/typeconst a "ss"const(a=3bf="yes"c=iotad)type a inttype(b stringc []byted boole fun(int) (string,error){})-------------------------------------------------------arrayfunc main() {var arr1 [5]intarr1 = [5]int{1, 3, 45, 8, 21}arr2 := [...]string{"go", "lang"}arr3 := new([4]int)*arr3 = [4]int{1, 2, 3, 4}arr3[0] = 99fmt.Println(arr1, arr2, arr3)var p *[5]int = &arr1x, y := 2, 3arr4 := [3]*int{&x, &y}fmt.Println(p, arr4)arr5 := [3][2]int{{3, 4}, {}}fmt.Println(arr5)}---------------------------------元素遍历func main() {a := [5]int{3, 23, 45, 23, 77}for i := 0; i < len(a); i++ {log.Printf("a[%d]=%d/n", i, a[i])}b := []string{"aa", "sfsf", "papa", "dkdk"}for i, ok := range b {log.Printf("a[%d]=%c/n", i, ok)log.Println(i, ok)}c := [5]int{99, 99, 99, 99, 99}for i, ok := range c {log.Println(i, ok)}}---------------------------------冒泡排序func main() {arr := []int{22, 15, 25, 18, 23}BubbleSort(arr)}func BubbleSort(a []int) {if len(a) < 1 {return}for i := 0; i < len(a); i++ {for j := i + 1; j < len(a); j++ {if a[i] > a[j] {a[i], a[j] = a[j], a[i]}}}fmt.Println(a)}-------------------------------------------------------slicefunc main() {arr := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}var s1 []ints1 = []int{2, 3, 4, 5}s2 := arr[1:6]s3 := arr[6:]s4 := s2[0:3]fmt.Println(s1, s2, s3, s4)s4[0] = 99fmt.Println(s1, s2, s3, s4)s5 := make([]string, 2, 5)s5 = []string{"hello", "world", "!"}s6 := new([]int)*s6 = []int{2, 3, 4, 5, 6, 9}//s6[3] = 4 数组切片指针不支持[]操作fmt.Println(s5, s6)s2 = append(s2, 33, 44, 55, 55, 6)//arr = append(arr, 3, 4) 只有切片才能用appendfmt.Println(s2, arr, len(s2), cap(s2))copy(s2, s3)fmt.Println(s2, s3, arr)}--------------------------------------------------------map操作func main() {var m1 map[int]intm1 = map[int]int{1: 1, 2: 2, 3: 3}m2 := map[int]string{1: "a", 2: "b"}m3 := make(map[int]int, 4)m3[1] = 33fmt.Println(m1, m2, m3)a := m2[2]fmt.Println(a)delete(m1, 2)fmt.Println(m1)m4 := make(map[int]map[int]string)fmt.Println(m4)//m4[1][1] = "OK" 必须先初始化外层第一个键的mapm4[1] = make(map[int]string) //初始化内层的mapm4[1][1] = "OK 1"m4[1][2] = "OK 2"fmt.Println(m4)m5 := make(map[int]map[int]string)a, ok := m5[2][3] //返回2个值,一个是键对应的值,一个是是否返回值,bool型fmt.Println(a, ok)if !ok {m5[2] = make(map[int]string)}m5[2][3] = "value and bool"a, ok = m5[2][3]fmt.Println(a, ok, m5)//-------------迭代操作,拷贝,改变值sm1 := make([]map[int]string, 5)for _, v := range sm1 {v = make(map[int]string, 1)v[1] = "OK"fmt.Println(v)}fmt.Println(sm1)sm2 := make([]map[int]string, 5)for i := range sm2 {sm2[i] = make(map[int]string)sm2[i][1] = "OK"fmt.Println(sm2[i])}fmt.Println(sm2)//----------------交换键和值的顺序m6 := map[int]string{1: "a", 2: "b", 3: "c", 4: "D", 5: "F"}m7 := make(map[string]int)for k, v := range m6 {m7[v] = kfmt.Println(k, v, m7)}fmt.Println(m7)}----------------------------------------------------------函数func main() {var1 := 99A(var1) //无返回值的函数就是一个表示式,不能使用赋值操作c:=A(var1)错误b := B(var1) //B有返回值可以作为一个值赋给变量,函数的调用fmt.Println(b, var1) //函数AB也是值传递,对实参没影响C(&var1) //传递的是实参的地址,修改他的内容*fmt.Println(var1)var s errorfmt.Println(s)f1(2, 4, 5, 7, 8)}func A(a int) {a = 1fmt.Println("func A", a)//值传递和指针传递}func B(a int) int {a = 2fmt.Println("func B", a)return a}func C(a *int) {*a = 9fmt.Println("func C", *a)}------------------------不定参,deferfunc f1(arg ...int) { //接受不定数量的参数,在函数体中,变量arg是一个int型的slicefor i, v := range arg {fmt.Println(i)fmt.Println(v)fmt.Printf("arg index:", i, "arg value:", v)//打印的值有点怪}}func main() {a := func() { //匿名函数,赋值给a,后面没有(),函数作为一个值fmt.Println("hello world")}a() //调用fmt.Printf("%T/n", a) //%T打印变量的类型f1()f()}func f1() {for i := 0; i < 5; i++ {defer fmt.Println(i) //延迟代码,后进先出的顺序,}}func f() (ret int) {defer func() { //defer访问返回值ret++}()return 0}------------------函数体内使用匿名函数作为值传递给变量func main() {var k = 4a := func(i int) func() {return func() {fmt.Println("i + k=", i+k)}}fmt.Printf("%T/n", a)b := a(3)b()}func main() {var k = 4a := func(i int) func() {return func() {fmt.Println("i + k=", i+k)}}(4)//这里加了()后表示已经调用了,a的类型已经变成了func()//但是不会打印任何东西,因为返回值是个闭包,里面的内容外部是看不见的//只有调用了内部的函数,闭包后才能显示打印,但不要再加参数fmt.Printf("%T/n", a)a()}------------------------匿名函数()问题func main() {f := func(i, j int) (result int) {result = i + jreturn} //--------创建匿名函数不执行,加了()就直接执行,这里要调用fmt.Fprintf(os.Stdout, "f=%v,f=%T,f(1,3)=%v/n", f, f, f(1, 3))//匿名函数调用,这里f的类型是func(int,int)int,和下面x,y不一样x, y := func(i, j int) (m, n int) {return j, i}(1, 9) //直接执行的匿名函数就可以当做一个值来传递,x,y的类型是intfmt.Fprintf(os.Stdout, "x=%d,x=%T,y=%d/n", x, x, y)}func main() {f := close(4) //调用了函数后,就得到了返回值,这个参数是x//故而f的类型是func(int) int,是close函数的返回值类型,即匿名函数类型,fmt.Printf("%T/n", f)b := f(1) //调用匿名函数后的返回值类型为int,这个参数是yfmt.Printf("b=%d,type=%T/n", b, b)}func close(x int) func(int) int { //调用close函数,return并不会执行打印的语句fmt.Println(x)return func(y int) int {fmt.Println(x, y)return x + y}}----------------------------------------------------------结构体type person struct {Name stringAge int}func main() {p1 := &person{"joe", 22}p2 := person{Name: "jim", Age: 25}p3 := &person{Name: "jack",Age: 20,}p4 := person{}fmt.Println(p1, p2, p3, p4)//A(*p1)B(p1)fmt.Println(p1, p2, p3, p4)}func A(p person) {p.Age = 33p.Name = "change p1"fmt.Println(p)}func B(p *person) {p.Age = 33p.Name = "change p1"fmt.Println(p)}---------------------匿名结构func main() {a := &struct {Name stringAge int}{Name: "joe",Age: 19,}fmt.Println(a)}---------------------嵌套embedding结构type person struct {sex string}type teacher struct {personName stringAge int}type student struct {personteacherName stringAge int}func main() {a := &person{}b := &teacher{}c := &student{}fmt.Println(a, b, c)a.sex = "male"b.person.sex = "female"b.Age = 22b.Name = "jack"c.Age = 99//遇到不同结构体的同名变量时,默认是第一层的变量的值fmt.Println(a, b, c)c.sex = "female"c.teacher.Name = "joe"fmt.Println(a, b, c)}----------------------------------------------------------方法type person struct {Name stringAge int}func (p *person) change() {//改为func (p person)后就是值拷贝,调用该方法后对实参是没有影响的p.Name = "has been changed name"fmt.Println(p)}func main() {a := &person{}//若将这里改为a:=person{},则后面的值就变为{},而不是&{}fmt.Println(a)a.change()fmt.Println(a)//因为传递的是指针,所有a的值被改变}-----------------------面向对象和面向过程的区别type interger intfunc (*interger) compare(a, b int) bool {return a < b}func (a interger) less(b interger) bool {return a < b}func it_less(a, b interger) bool {return a < b}func main() {//面向对象的用法var c intergerfmt.Println(c.compare(5, 3)) //用不到接收者就省略,但是类型一定要有var d interger = 1fmt.Println(d.less(3)) //d就是方法的接收者,//面向过程的用法fmt.Println(it_less(5, 3))}---------------------------求矩形的面积和周长type rect struct {width, height int}func (r *rect) area() int {return r.width * r.height}func (r rect) perim() int {//若不需要用到实参,则值址传递无所谓,尽量用&return 2*r.width + 2*r.height}func main() {r := rect{width: 10, height: 5}fmt.Println("area=", r.area(), "perim=", r.perim())rp := &rfmt.Println("area=", rp.area(), "perim=", rp.perim())}--------------修改对象的值type Interger intfunc (a *Interger) add(b Interger) { //接收者为指针,可以修改实参的值,若是a Interger则不能改变,拷贝*a += b}func main() {var a Interger = 1fmt.Println(a)a.add(4)fmt.Println(a)}------------------------------------------------------接口--------------------------接口实现排序package mainimport "fmt"type Sorter interface {len() intless(i, j int) boolswap(i, j int)}type xi []inttype xs []stringfunc (p xi) len() int {return len(p)}func (p xi) less(i, j int) bool {return p[i] > p[j]}func (p xi) swap(i, j int) {p[i], p[j] = p[j], p[i]}func (p xs) len() int {return len(p)}func (p xs) less(i, j int) bool {return p[i] > p[j]}func (p xs) swap(i, j int) {p[i], p[j] = p[j], p[i]}func Sort(x Sorter) {for i := 0; i < x.len(); i++ {for j := i + 1; j < x.len(); j++ {if x.less(i, j) {x.swap(i, j)}}}}--------------------------接口赋值type Interger intfunc (a Interger) Less(b Interger)bool{return a<b}func (a *Interger) Add(b Interger){*a=b}//为新类型添加方法type LessAdder interface{Less(b Interger) boolAdd(b Interger)}//定义我们自己的接口er,怎样给接口赋值?对象实例和接口var a Interger =1//Interger类型的对对象实例,新建一个接口类型实例//var file package.LessAdd=new(File)var b LessAdder=&avar b LessAdder=a//利用第一个语句&a,go语言可以根据定义的Less方法,自动生成一个新的Less()方法:func (a *Interger) Less(b Interger) bool{return (*a).Less(b)}//这样*Interger就即存在Less()方法也存在Add()方法,满足接口。但是,根据func(a Interger)Add(b Interger)无法自动生成下面这个成员方法func (a Interger)Add(b Interger){(&a).Addr}//因为,它改变的只是函数参数a,对外面的实参没有影响//因此类型Interger只存在Less()方法,缺少Add()方法,不满足接口。--------------------------------type Lesser interface{//新定义一个接口Less(b Interger) bool}var a Interger=1var b1 Lesser=avar b1 Lesser=&a这两种赋值方法都可以编译通过,都实现了接口里面的方法-----------------------------接口查询,是否实现了接口------------------------------------------------------并发func main() {a := xi{15, 2, 66, 24, 19}b := xs{"sf", "pa", "dk"}Sort(a)Sort(b)fmt.Println(a, b)}func main() {go func() {fmt.Println("one thread")//go开启一个新的线程,和main执行顺序不确定}()time.Sleep(time.Second * 5)fmt.Println("main thread")}--------------------channelvar c chan int //可用来发送和接收int类型的值//var s chan <-string 仅可用来发送string类型的值//var f <-chan float32 仅可用来接收int类型的值//var s1 <-chan struct{} 空结构体管道,仅用于发送信号,不是传递数据func main() {c = make(chan int)//c1 :=make(chan *byte,10) 带缓冲的byte类型指针管道go func() {fmt.Println("one thread")c <- 1}()go func() {fmt.Println("Second thread")time.Sleep(time.Second)c <- 2}()go func() {fmt.Println("third thread")c <- 3}()fmt.Println("main thread")<-c<-c<-cclose(c)}-----------------------closefunc main() {ch := make(chan string)go func() {ch <- "hello"//只发送一次close(ch)//标志着不会再向管道里发送值}()fmt.Println(<-ch)//输出字符串"hello"fmt.Println(<-ch)//输出字符串零值,为空""fmt.Println(<-ch)再次打印空值v, ok := <-ch//v的值为空"",ok的值为falsefmt.Println(v, ok)}----------------------selectfunc main() {c1 := make(chan string)c2 := make(chan string)go func() {//time.Sleep(time.Second * 2)c1 <- "one"}()go func() {//time.Sleep(time.Second * 2)c2 <- "two"}()for i := 0; i < 2; i++ {select {case msg1 := <-c1:fmt.Println(msg1)case msg2 := <-c2:fmt.Println(msg2)}}}---------------------------共享数据func main() {wait := make(chan int)n := 0 //所有的goroutine共享的数据//不应该通过共享数据来通信,而要通过通信来共享数据go func() {s := 99 //仅为一个goroutine可见的局部变量n++wait <- n //数据从一个goroutine离开,发送,也起到同步作用wait <- sclose(wait)fmt.Println(<-wait)}()go func() {n++<-wait //从一个管道接收<-waitclose(wait)}()s := <-waitfmt.Println(n)fmt.Println(s)}----------------------------------互斥锁import ("fmt""sync")type s struct { //一个并发的数据结构mu sync.Mutex //锁,一次只能被一个goroutine访问n int}//为该结构添加2个方法Add(int) value() intfunc (a *s) Add(n int) {a.mu.Lock() //等待锁释放,然后持有它a.n += na.mu.Unlock() //释放锁}func (a *s) value() int {a.mu.Lock()n := a.na.mu.Unlock()return n}func main() {wait := make(chan struct{})var n sgo func() {n.Add(1) //一次访问close(wait)}()n.Add(1) //另一个并发访问<-waitfmt.Println(n.value())}---------------------------------------------------------HTTPfunc main() { http.ListenAndServe(":8080", nil)}//当第二个参数是nil时,http内部会自己建立一个叫DefaultServeMux//的ServeMux,要向这个mux里面注册的话,就要用http.HandleFunc("/",sayhello)-------------------------type a struct{}func (*a) ServeHTTP(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello world version 1.")}func main() { http.ListenAndServe(":8080", &a{}) //第2个参数需要实现Handler的struct,a满足}---------------------------type b struct{}func (*b) ServeHTTP(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello")}func main() { mux := http.NewServeMux() //ServeMux有一张map表,key是r,URL.String(),value记录的是一个方法 //类似ServeHTTP,别名叫HandlerFunc mux.Handle("/h", &b{}) //用来注册HandlerFunc //ServeMux里面实现了2个方法Handle,ServeHTTP,这样实现了Handler接口 //才能当监听函数的第二个参数传递 http.ListenAndServe(":8080", mux)}----------------------------func main() {//跳过结构b,用mux.HandleFunc()来注册func到map表中 mux := http.NewServeMux() mux.HandleFunc("/h", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello") }) mux.HandleFunc("/bye", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "byebye") }) mux.HandleFunc("/hello", sayhello) http.ListenAndServe(":8080", mux)}func sayhello(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello world")}------------------------------func myhandle(w http.ResponseWriter, r *http.Request) {path := r.URL.String()fmt.Fprintf(w, "hi there,i love %s!/n", path[1:])}func main() {http.HandleFunc("/", myhandle)http.ListenAndServe(":1000", nil)}-----------------------通过服务器给客户端发送文件type Page struct {Title stringBody []byte}func (p *Page) save() error {filename := p.Title + ".txt"return ioutil.WriteFile(filename, p.Body, 0600)}func loadpage(title string) (*Page, error) {filename := title + ".txt"body, err := ioutil.ReadFile(filename)if err != nil {return nil, err}return &Page{Title: title, Body: body}, nil}func myhandle(w http.ResponseWriter, r *http.Request) {title := r.URL.Path[4:]p, _ := loadpage(title)fmt.Fprintf(w, "<h1>%s</h1><div>%s<div>", p.Title, p.Body)}func main() {http.HandleFunc("/my/", myhandle)http.ListenAndServe(":1000", nil)}---------------------------一个简单的传送html数据package mainimport ("fmt""io/ioutil""net/http")type Page struct {Title stringBody []byte}func loadpage(title string) (*Page, error) {filename := title + ".txt"body, err := ioutil.ReadFile(filename)if err != nil {return nil, err}return &Page{Title: title, Body: body}, nil}func viewhandle(w http.ResponseWriter, r *http.Request) {title := r.URL.Path[len("/view/"):]p, _ := loadpage(title)fmt.Fprintf(w, "<h1>%s</h1><div>%s<div>", p.Title, p.Body)}func edithandle(w http.ResponseWriter, r *http.Request) {title := r.URL.Path[len("/edit/"):]p, err := loadpage(title)if err != nil {p = &Page{Title: title} //如果文件不存在就创建}fmt.Fprintf(w, "<h1>Editing %s</h1>"+"<form action=/"/save/%s/" method=/"POST/">"+"<textarea name=/"body/">%s</textarea><br />"+"<input type=/"submit/" value=/"save1/">"+"</form>",p.Title, p.Title, p.Body)}func main() {http.HandleFunc("/view/", viewhandle)http.HandleFunc("/edit/", edithandle)http.HandleFunc("save", savehandle)http.ListenAndServe(":1000", nil)}--------------------利用html模板/渲染模板http://godoc.golangtc.com/doc/articles/wiki/import ("html/template""io/ioutil""net/http")type Page struct {Title stringBody []byte}func (p *Page) save() error {filename := p.Title + ".txt"return ioutil.WriteFile(filename, p.Body, 0600)}func loadpage(title string) (*Page, error) {filename := title + ".txt"body, err := ioutil.ReadFile(filename)if err != nil {return nil, err}return &Page{Title: title, Body: body}, nil}func viewhandle(w http.ResponseWriter, r *http.Request) {title := r.URL.Path[len("/view/"):]p, err := loadpage(title)if err != nil {p = &Page{Title: title}//访问不存在的网页时,显示空内容//http.Redirect(w, r, "/edit/"+title, http.StatusFound)return}t, _ := template.ParseFiles("view.html")t.Execute(w, p)}func edithandle(w http.ResponseWriter, r *http.Request) {title := r.URL.Path[len("/edit/"):]p, err := loadpage(title)if err != nil {p = &Page{Title: title} //如果文件不存在就创建}t, _ := template.ParseFiles("edit.html")t.Execute(w, p)}func savehandle(w http.ResponseWriter, r *http.Request) {title := r.URL.Path[len("/save/"):]body := r.FormValue("body")p := &Page{Title: title, Body: []byte(body)}p.save()//http.Redirect(w, r, "/view/"+title, http.StatusFound)}func main() {http.HandleFunc("/view/", viewhandle)http.HandleFunc("/edit/", edithandle)http.HandleFunc("/save/", savehandle)http.ListenAndServe(":1000", nil)}view.html<h1>{{.Title}}</h1><p>[<a href="/edit/{{.Title}}">edit</a>]</p><div>{{printf "%s" .Body}}</div>edit.html<h1>Editing {{.Title}}</h1><form action="/save/{{.Title}}" method="POST"><div><textarea name="body" id="t1" cols="80" rows="20">{{printf "%s" .Body}}</textarea></div><div><input type="submit" value="save"></div></form>--------------------------------增加安全性import ("errors""html/template""io/ioutil""net/http""regexp")var templates = template.Must(template.ParseFiles("edit.html", "view.html"))var validPath = regexp.MustCompile("^/(edit|save|view).([a-zA-Z0-9]+)$")//这个函数会解析和编译这个正则表达式,返回一个指针和错误值type Page struct {Title stringBody []byte}func (p *Page) save() error {filename := p.Title + ".txt"return ioutil.WriteFile(filename, p.Body, 0600)}func loadpage(title string) (*Page, error) {filename := title + ".txt"body, err := ioutil.ReadFile(filename)if err != nil {return nil, err}return &Page{Title: title, Body: body}, nil}func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {err := templates.ExecuteTemplate(w, tmpl+".html", p)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}err = t.Execute(w, p)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)}}func getTitle(w http.ResponseWriter, r *http.Request) (string, error) {m := validPath.FindStringSubmatch(r.URL.Path)if m == nil {http.NotFound(w, r)return "", errors.New("Invalid page title")}return m[2], nil //title的值在第二个表达式里面}func viewhandle(w http.ResponseWriter, r *http.Request) {title, err := getTitle(w, r)if err != nil {return}p, err := loadpage(title)if err != nil {http.Redirect(w, r, "/edit/"+title, http.StatusFound)return}renderTemplate(w, "view", p)}func edithandle(w http.ResponseWriter, r *http.Request) {title, err := getTitle(w, r)if err != nil {return}p, err := loadpage(title)if err != nil {p = &Page{Title: title} //如果文件不存在就创建}renderTemplate(w, "edit", p)}func savehandle(w http.ResponseWriter, r *http.Request) {title, err := getTitle(w, r)if err != nil {return}body := r.FormValue("body")p := &Page{Title: title, Body: []byte(body)}err = p.save()if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}http.Redirect(w, r, "/view/"+title, http.StatusFound)}func main() {http.HandleFunc("/view/", viewhandle)http.HandleFunc("/edit/", edithandle)http.HandleFunc("/save/", savehandle)http.ListenAndServe(":1000", nil)}---------------标准web代码框架package mainimport ("flag""html/template""io/ioutil""log""net""net/http""regexp")var (addr = flag.Bool("addr", false, "find open address and print to final-port.txt"))type Page struct {Title stringBody []byte}func (p *Page) save() error {filename := p.Title + ".txt"return ioutil.WriteFile(filename, p.Body, 0600)}func loadPage(title string) (*Page, error) {filename := title + ".txt"body, err := ioutil.ReadFile(filename)if err != nil {return nil, err}return &Page{Title: title, Body: body}, nil}func viewHandler(w http.ResponseWriter, r *http.Request, title string) {p, err := loadPage(title)if err != nil {http.Redirect(w, r, "/edit/"+title, http.StatusFound)return}renderTemplate(w, "view", p)}func editHandler(w http.ResponseWriter, r *http.Request, title string) {p, err := loadPage(title)if err != nil {p = &Page{Title: title}}renderTemplate(w, "edit", p)}func saveHandler(w http.ResponseWriter, r *http.Request, title string) {body := r.FormValue("body")p := &Page{Title: title, Body: []byte(body)}err := p.save()if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}http.Redirect(w, r, "/view/"+title, http.StatusFound)}var templates = template.Must(template.ParseFiles("edit.html", "view.html"))func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {err := templates.ExecuteTemplate(w, tmpl+".html", p)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)}}var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {m := validPath.FindStringSubmatch(r.URL.Path)if m == nil {http.NotFound(w, r)return}fn(w, r, m[2])}}func main() {flag.Parse()http.HandleFunc("/view/", makeHandler(viewHandler))http.HandleFunc("/edit/", makeHandler(editHandler))http.HandleFunc("/save/", makeHandler(saveHandler))if *addr {l, err := net.Listen("tcp", "127.0.0.1:0")if err != nil {log.Fatal(err)}err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644)if err != nil {log.Fatal(err)}s := &http.Server{}s.Serve(l)return}http.ListenAndServe(":8080", nil)}--------------------------------------------------input/outputtype Reader interface{Read(p []byte)(n int,err error)}type Write interfaace{Write(p []byte)(n int,err error)}//将len(p)个字节读取到p中,返回读取的字节数,0<=n<=len(p)//所有实现了Read方法的类型都实现了io.Reader接口--------------------------------------------------读写文件type Page struct {Title stringBody []byte}func (p *Page) save() error {filename := p.Title + ".txt"return ioutil.WriteFile(filename, p.Body, 0600)}func loadPage(title string) (*Page, error) {filename := title + ".txt"body, err := ioutil.ReadFile(filename)if err != nil {return nil, err}return &Page{Title: title, Body: body}, nil}func main() {p1 := &Page{Title: "Testpage", Body: []byte("This is a simple Page.")}p1.save()p2, _ := loadPage("Testpage")fmt.Println(string(p2.Body))}----------------func main() {buf := make([]byte, 1024)f, _ := os.Open("E://ljl_doc//study//victory.txt")// linux上是/etc/passwdn, _ := f.Read(buf)os.Stdout.Write(buf[:n])}

版权声明:本文为博主原创文章,未经博主允许不得转载。



分享给朋友:
您可能感兴趣的文章:
随机阅读: