学习笔记暂时不知道写啥_第1页
学习笔记暂时不知道写啥_第2页
学习笔记暂时不知道写啥_第3页
学习笔记暂时不知道写啥_第4页
学习笔记暂时不知道写啥_第5页
已阅读5页,还剩227页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

暂时不知道写啥::qyuhen@hotmail2012-01-15(releaser6039516)。2012-01-17interfacemethod2012-01-28更新细节2012-01-302012-02-032012-03-29Go1Released!2012-04-01Command2012-04-222012-04-252012-06-082012-06-151022012-09-042012-11-22interface、cgointerfacegobuildgcflags 第一部分Go语 第1章基 第2章函 26 8Call 第3章Array、Slices和 1 32 3 第4章 44方 5内存布 46字段 67第5章接 54空接 55类型推 6接口转 第6章并 1 2 第7章程序结 章进1运行 2内存分 83内存布 84反 5数据竞 86 第9章工 1命令行工 92GDB调 93条件编 94跨平台编 5程序测 6开发工 第二部分标准 第10章 1 102 第11章 第12章 121 122 123 124 125 126 第13章 第14章 第15章 15116171819202122232424124224324424524624724825262612622727127227327428281283284285293031311312313314323213223233243253333133234341342343 附 Go源码阅读指 1内存分 2回 3 Go函数调用反汇 第一部分Go暂时不知道写啥代码测试环境Go1OSX10第1变bool:integers:floats:0string:推断只是一种简便的代码语法糖,不同于Javascript、Python,我们不能修改变量的类型。varvara=varbstring=" varcboolfuncmain()println(a,b,}aa:=varx,y 类型相同的多个变var 类型不同的多个变)varc,dint=1,指定类型,多个变量类型相同vare,f=123,g,h:=123,"//自动推断,多个变量类型按初始值推断//自动推断,多个变量类型按初始值推断sasa:=[]int{1,2,i:=i,sa[i]=1,//setsi=1,sa[0]=sb:=[]int{1,2,j:=sb[j],j=2,println(sb[j],

//setssb[0]=2,j=sc:=[]int{1,2,sc[0],sc[0]=1,

//setssc[0]=1,thensc[0]=2(sosc[0]=2atfuncfunctest()(int,{return123,}funcmain()a,_:=test()}packagepackageimport)//Error:importedandnotused:funcmain()vara=}//Error:adeclaredandnot基本类类长说114int32。UnicodeCodePoint1-128~127;0~2-32768~32767;0~4-21~21亿0~42类长说8488含了Min/Max开头的各类型最小、最大值常量。为类似C++/C#的。funcfuncmain()varmmap[string]intm["a"]=1}输出panic:runtimeerror:assignmenttoentryinnil funcfuncmain()vara=//if//ifa{println("True")ifa>0{println("True")//Error:non-boola(typeint)usedasif}类型转funcfuncmain()a:=b:=c:=fmt.Printf("%x\n", 截短长fmt.Printf("%d\n", 截断小fmt.Printf("%f\n",}输出<-chanint(c)(<-chanint)(c)

//sameas//pisconvertedto//sameas<-(chan//cisconvertedto(<-chan常常量必须是编译期能确定的Number(char plex)、String和bool类型。可以constxuint32=123consty=" consta,b,c="meat",2,"veg"const(z=falsea=123

同样支持一次定义多个常量)funcfunc{consta="abc")println(a,}输出abcabc()constconsta=b=c=)varvarmillionint=varbbyte=//floatsyntaxOK//inttoconst)const)Sunday=//////////////typetypeByteSizeint64const(_=KBByteSize=1<<(10*iota))忽funcfuncmain()println(GB,GB/1024/1024/}输出1073741824 constconstA,B=iota,iotaC,DE,)funcmain()println(C,D,E,}输出112 func{consta=iotacd="ha"f=gh=iota

//////独立没有使用iota恢复,所以和d和f值相7,恢复iotacouter,继续按行递增//)println(a,b,c,d,e,f,g,h,}输出012haha1001007 字符string是不可变值类型,指针指向一个UTF-8byte数组。变长编码方式,每个Unicode字符可能需要1~4个byte,不同于Java/C#/Python这类语言使用UTF-16/UTF-32固定宽NULL\0:struct{byte*int32字符funcfuncmain()b:=b[1]=b[0]我}输出main.go:main.go:constant25105overflowsmake:***[_go_.6]Errorss:=误(Error:invalidoperation:+idealstring)。ss:="abc"",importimport)funcmain()a,b,c:="a","b",s:=strings.Join([]string{a,b,c},"")}funcfuncmain()sb:= o}输出oofuncfuncmain()s:="abcdefg"sub:=s[1:3]fmt.Printf("%T=%v\n",sub,}输出stringstring=

//==//bytes->//Unicodeints->UTF-8//UTF-8string->//UTF-8string->Unicodefuncfuncmain()s:=varcbyte=按索引fmt.Printf("%c,%02x\n",c,bs:=[]byte(s) 转换为bytes,以便修改bs[1]='B'}输出b,b,funcfuncmain()//UTF-8编码格 的字符s:= println("utf-8string:",s,stringtobytesbs:=bs[0]=fori:=0;i<len(bs);{fmt.Printf("%02x",}bytesstringto转换成u:=println("unicodelen=",//显示UnicodeCodePointfori0;ilen(u);i++{fmt.Printf("%04x",}按照unicodeu[4]龙unicodestring}输出utf-8utf-8string:413ae4b8ade59bbde4babaunicodelen=0061003a4e2d56fd4ebaa:funcfuncmain()s:= fori:=0;i<len(s);{fmt.Printf("%c\n",}fori,c:=range{fmt.Printf("%d=%c\n",i,}输出ä丸-å036 关,比如在中文里,"我"是一个字符,不能生生将其当作几个字节的拼接。早期的计算机系统编码方案主要适应英文等字母语言体系,ASCII编码方案的容量足以表达所有的字符,于是界上并非只有英文一种字符,中文等东亚语言体系的字符数量就无法用ASCII容纳,人们只好用2个或者更多的字节来表达一个字符,于是就有了GB2312、BIG5等等种类繁多且互不兼容的编码方案。 的字符编码方案,这就是Unicode编码方案。Unicode使得我们在一个系统中可以同时处理和显示不同国家Unicode"我"对应的数字是25105(\u6211)。Unicode字符集(UCS,UnicodeCharacterSet)有UCS-2、UCS-4两种标准。UCS-2U+FFFFUCS-440,也就是说最多可以有2^31个字符,几乎容纳了全世界所有的字符。Unicode只是将字符和数字建立了 示,这其中还涉及到不同计算机架构的大小端问题(BigEndian,LittleEndian)。于是有了几种将Unicode字符数字转换成字节的方法:Unicode字符集转换格式(UCSTransformationFormat),缩写UTF。UTF-16:用2字节无符号整 Unicode字符,与UCS-2对应,适合处理中文UTF-32:用4字节无符号整 Unicode字符。与UCS-4对应,多数时候有点浪费内存空间UTF-8具有非常良好的平台适应性和交互能力,因此已经成为很多操作系统平台的默认 UTF-16因为等长,浪费空间较少,拥有更好的处理性能,包括.NET、JVM等都使用2字节的Unicode另外,按照大小端划分,UTF又有BE和LE两种格式,比如UTF-16BE、UTF-16LE等。为了让系统能自动BELEBOM信息,"FEFF"BE,"FFFELE。后面还会有一两个字符用来表示UTF-8或UTF-32。运算优先运算说高 & ^ >低&=2AND,都为|=OR,至少一个为^=XOR,只能一个为=4ANDNOT,bitclear。从a上清除所有b的标志位11在0、1、3上设置了标志,检查6这三个二进制位,如果是1就改为0即可演示func{a:=a=a|(1<<3)a=a|(1<<

在bit3上设置标志位(从bit0开始算在bit6上设置标志//a=72=0100a=a&^(1<<bit6上的标志位,a80000}funcfunc{i:=p:=//a:=i++a:=//syntaxerror:unexpected++,expectingsemicolonornewlineor//b:=b:=//syntaxerror:unexpected++,expectingsemicolonornewlineorprintln(a,}+&()-|-<[]*^>{}/=,;%-!.:指针类型的符号"*"总是和类型放在一起,而不是紧挨着变量名。同样支持指针的指针(**T)。varvara,btypetypeUser{IdintNamestring}funcmain()i:=varp*int=取地//invalidoperation:p+=1(mismatchedtypes*intand取up:=&User{1,"Jack"}up.Id=100直接操作指针对象成u2:=*upu2.Name="Tom"fmt.Println(up,拷贝对}输出&{100&{100Jack}{100constconstNint=funcmain()x:=p:= //*int->p2 Pointer*[4]int,注意slice的内存布局array是不同的数组类型元素长度必须是常量fori,m:=0,len(p2);i<m;i++fmt.Printf("%02X",}}输出341200 typetypeUser{IdintNamestring}funcfuncmain()p:=&User{1,"User1"varnpuintptr=uintptr(unsafe.Pointer(p))+unsafe.Offsetof(p.Name)varname*string=(*string)(unsafe.Pointer(np))}输出保留控制结funcfunc{a:=ifa>0a+=}elseifa=={a=}elsea-=}左大括号必须写在这,否则被解释为"ifa0;"导致编译出错注意左大括号位置注意左大括号位置 ifa>0{a+=100}else{a-=100 隐藏block外的同名变量)。ififerr:= od(0664);err!=returnerr}很遗憾,Go"?:"Python"andor"boolforforinit;condition;post{}forcondition{}forforfori,j:=0,len(a)-1;i<j;i,j=i+1,j-1a[i],a[j]=a[j],}funcfuncmain()l:=func(sstring){println("getlength")return}ss:=fori:=0;i<l(ss);{} fori,m:=0,l(ss);i<m;{ 输出getfuncfuncmain()fori,c:=range{fmt.Printf("s[%d]=%c\n",i,}输出s[0]s[0]=s[1]=s[2]=用"_"这个特殊变量。或者只要序号。case处理,则须显式执行fallthrough。funcmain()switcha:=5;{case0,case100:case

逗号指定多个分什么都不做。不是多行代码,无需使用{}进入后续case处} 输出bbcswitchtrueifelseifelse {a:=switchcasea>1:println("a")casea>2:println("b")default:println("c")}}funcfuncmain()switcha:=5;}}Goto,Break,funcmain()forfori:=0;i<10;i++ifi>2{breakLABEL1}else{funcmain()forfori:=0;i<10;i++ifi>2{breakLABEL1}else{println("L1:",i)}}fori:=0;i<5;{forprintln("L2:",i)continueLABEL2}} 输出L1:L1:L1:L1:L2:L2:L2:L2:L2:自定义类型包括bool、int、string等,而未命名类型有array、slice、map、channel、function等。)funcfuncmain()varastruct{x,yint}varbstruct{x,ya.x=a.y=2b=a}typetypeMyInttypeIntPointertypetypeData{x,y}typeTester{test(int)(string,}funcmain()varx=varpIntPointer=&x;vard=Data{1,2}println(d.x,d.y)p2:=&Data{y:200}println(p2.x,}type定义的新类型(基于其他类型)并不是一个别名,而是一个全新的类型。除了和底层类型拥有相同的数据结构外,它不会"继承"包括方法在内的任何信息,这与struct字段嵌入完全不是事。typetypeMyInttypeMyIntSlicefuncmain()varaMyInt=//varbint=avarbint=int(a)//cannotusea(typeMyInt)astypeintin//varcMyInt=b //cannotuseb(typeint)astypeMyIntinassignmentvarcMyInt=MyInt(b)println(a,b,}typetypeMyIntSlicefuncmain()varaMyIntSlice=[]int{1,2,3}varb[]int=aprintln(a,}初始vard1[2]int=[2]int{1}vard2=[2]int{2}d3:=[2]int{3

//太繁琐,但不能省略右边的类型在函数外部需要var//函 这样最简洁ss[]byte{,m"a":这个逗号是必须的,或以}结尾u:=structageint}这个逗号是必须的fmt.Println(s,m,内置函closechannel:appendslice(在其尾部添加copy:在不同slice间数据print/printlnformatfmtcomplex/real/imag:复数处理panic/recover:第2多返回值函数闭包函数定接收多个参数,无返回值functest(a,bint,c{println(a,b,}单个返回funcadd(a,bint){returna+}funcmain()test(1,2, //12println(add(1, //}以return、panic、goto结束条件选择if 所有分支都能终止breakswitch、selectdefault函数类typetypecallbackfunc(s 定义函数类funcfunctest(a,bint,sumfunc(int,int)int){println(sum(a,b))}callbackfuncmain()varcbcallback=func(s{} o,test(1,2,func(a,bint)intreturnabJavascript}输出o,o,3多返回值、命名返回参Pythontuple类型。对于不想要的返回值,可用特殊变多个返回funcswap(a,bint)(int,{returnb,}命名返回参funcchange(a,bint)(x,y{x=a+100y=b+100也可以写成returnx,}funcmain()a,b:=1,a,bswap(a, 21,可以用_接收不想要的返回println(a,c,d:=change(1,println(c,//101}funcfunctest(aint)(x{ifx:=10;a>0{block变量x隐藏了命名返回值x}}}funcmain()}输出./main.go:./main.go:xisshadowedduringfuncfunctest(aint)(x{ifx:=10;a>0{returnx+1}这样就没问题了这个不受ifblock影响}funcfuncargs()(int,{return1,}functest(iint,s{fmt.Println(i,}也可以用变funcmain()}输出11变开,否则就当作单个参数处理了。和Python*args方式相同。funcsum(sstring,args{varxfor_,n:=rangeargs{x+=n

注意语法格}println(s,}funcfuncmain()sum("1+2+3=",1,2,x:=[]int{0,1,2,3,sum("0+1+2=",}函数、闭/*/*闭包支持funcclosures(xint)(func(int)int)//返 函returnfunc(yint){returnx+}}funcmain()f:=closures(10)} 函数 了////funcfuncmain()varfsfori:=0;i<3;i++fs=append(fs,func(){return}for_,f:=range{fmt.Printf("%p=%v\n",f,}0x421410000x42141000=0x42141040=0x42141080=funcfunctest(xint){fmt.Printf("%p=%v\n",&x,returnfunc()fmt.Printf("%pfmt.Printf("%p=%v\n",&x,}}funcmain()f:=test(100)}0x4212f1000x4212f100=0x4212f100=funcfunc{try...function}finally}}functest(a,bint)intdeferprintln("defer1:",a,"/",defer{println("defer2:",a, //注意不仅仅是定义一 函数functest(a,bint)intdeferprintln("defer1:",a,"/",defer{println("defer2:",a, //注意不仅仅是定义一 函数,还要带上"()"进行调用returna/}funcmain()a:=test(10,b:=test(10,通过输出会发现,就算发生严runtimeerror,defer依然被执行print(a,}输出defer2:defer2:10defer1:10/defer2:10defer1:10/panic:panic:runtimeerror:integerdivideby[signal0x8code=0x7addr=0x20c9funcfuncWriteData(file*File,mu*Mutex,data{mu.Lock()//writedata}funcfunctest(a,bint)(c{deferfunc(){c+=100c=a+b}funcmain()x:=test(10,0)}输出 defer在函数退出时执行,不过输出的确实是早先抢回家的数据。可以考虑用指针或者闭包代替参funcfunc{x:=deferfunc(a{println("a=",deferprintln("print=",x)x+=100}输出printprint=a=funcfuncmain()varfs=fori:=0;i<4;i++deferprintln("deferi=",defer:直接获取当前i的deferfunc()println("defer_closure",i)}()defer_closure:在defer函数中使用闭fs[i]=func(){println("closurei=",i)}//closure:仅持有i ,在函数执行时再获}for_,frangefsf() 执行闭包函}输出closurei=4closurei=4closurei=4closurei=4defer_closureclosurei=4closurei=4closurei=4closurei=4defer_closuredefer_closuredefer_closuredeferi=3deferi=2deferi=1deferi=Panic、Go没有try 后在defer中用recover函数捕获错误。funcfuncfuncrecover()如果不recover捕获panic"调用(callstack)"向外层传递。recoverdefercatch那样恢复到后续位置继续执packagepackageimport)funcTest(ffunc()int)deferdeferfunc()iferr:=recover();err!=}x:=f()}func{a:=Test(func(){return100/输出main.go:11main.go:11main.go:24(0x21b6)_func_002:return100/amain.go:16(0x2031)Test:x:=f()main.go:25(0x209c)main:2012/07/2500:41:26runtimeerror:integerdividebypanic(interface的错误对象,但规范中总是使用error接口类型。可使用fmtErrorf(format,)、errorsNew(text)便捷创建错误对象。TheTheconventionintheGolibrariesisthatevenwhenapackageusespanicinternally,itsexternalAPIpresentsexpliciterrorreturnCallfuncfunctest()}func{}输出8550/Users/yuhen/.../main.go13 funcfunctest()ps:=make([]uintptr,count:=runtime.Callers(0,fori:=0;i<count;i++f:=runtime.FuncForPC(ps[i])fmt.Printf("%d,%s\n",i,f.Name())}}funcmain()a:={}}输出0,0,1,2,3,4,5,packagepackageimport)functest(){}funcmain(){p:=reflect.ValueOf(test).Pointer()f:=runtime.FuncForPC(p)fmt.Printf("%p,%#x\n",test,}&{main.test&{main.testmain.go[1472]819281939800x2000,第3章Array、Slices和度是类型的组成部分,也就是说"[10]int"和"[20]int"是完全不同的两种数组类型。varvaraa[1]=//所有元素自动被初始化为fori:=0;i<len(a);{}a:=[10]int{1,2,3,4b:=[...]int{1,2c:=[10]int{2:1,5:100

//未提供初始化值的元素为默认值由初始化列表决定数组长度,不能省略"...",否则就成slice了按序号初始化元x,x,y:=1,varp1*[2]int=&[2]int{x,y}varp2[2]*int=[2]*int{&x,&y}fmt.Printf("%#v\n",p1)fmt.Printf("%#v\n",输出&[2]int{1,&[2]int{1,[2]*int{(*int)(0x4212f100),但不支持">"、"<"等比较操作符。println([1]string{"a"}println([1]string{"a"}==funcfunctest(x*[4]int)fori:=0;i<len(x);{}//用指 数组语法并没有什么不同,比C更直观x[3]=}funcmain()xx:=&[4]int{2:100,1:200}funcfunctest(a{a[2]=}用指针直接操作木有压力funcmain()vara=new([10]int)返回指针fmt.Println(a,}输出&[001000000000] funcfuncmain()vara=[3][2]int{[...]int{1,2},[...]int{3,4}}varb=[3][2]int{{1,2},{3,4}}c:=[...][2]int{{1,2},{3,4},{5,6}c[1][1]=第二个维度不能用fmt.Println(a,"\n",b,"\n",c,len(c),}[[1[[12][34][0[[12][34][0[[12][3100][56]]3typetypeUser{IdintNamestring}funcmain()a:=[...]User{0,"User0"{1,"User1"}b:=[...]*User{0,"User0"{{1,"User1"}}输出[{0[{0User0}{1[0x421223400x42122320]&{1{//mustnotmove//actual//numberof//allocatednumberofslice是类型,默认值为nil。可以用内置函数len()获取长度,cap()获取容量。使用索引时,出0到len-1范围。和数组之类型不同,类型slice赋值不会底层数组。然后将所需的数据copy过去。funcmain()x:=[...]int{0,1,2,3,4,5,6,7,8,9vars1[]int=//内容包括x[1],s2:=//x[4]~x[len-s3:=//x[0]~}s4:=//x[0]~x[len-输出[1[1[4[45678[01234[012345678funcfuncmain()x:=[...]int{0,1,2,3,4,5,6,7,8,9}s:=x[1:3]s[0]=对slice的修改实际上是对原数组的修改,注意序号的差异x[2]=对数组修改会影响slice}输出[0[01002345678[100funcfunctest(ss[1]=100}总是指向同一个数组funcmain()s:=[]int{0,1,2类型,不用担 底层数组}输出[0[01[0100果忽略cap参数,则cap=len。funcmain()s1:=make([]int,10)s1[1]=100fmt.Println(s1,len(s1),

//相当于s2:=make([]int,5,s2[4]=fmt.Println(s2,len(s2),}输出[0[010000000000]10[0000200]5 cap是slice非常重要的属性,它表示了slice可以容纳的最大元素数量。在初始创建slice对象时cap=array_length-slice_start_indexslice在数组上的开始位置到数组结尾的元素在cap允许的范围内我们可以reslice,以便操作后续的数组元素。超出cap限制不会导致底层数组重新分配,只会"sliceboundsoutofrange"错误。funcfuncmain()a:=[...]int{0,1,2,3,4,5,6,7,8,9s1:=//[56],len=2,cap=s1=//[5,6,7,8],len=4,cap=//注意 过cap的限制是在slice上重新切分,不是Array,因此序号是以slice为准}funcfuncmain()s1:=make([]int,3,//添加数据,未超出底层数组容量限制s2:=append(s1,1,2,append不会调整slice//s1==[000]len:3cap:6fmt.Println(s1,len(s1),cap(s1))注意append是追加,也就是说在s1尾部添加//s2==[000123]len:6cap:6fmt.Println(s2,len(s2),cap(s2))//追加的数据未超出底层数组容量限制通过调整s1,我们可以看到依然使用的是原数组//s1==[000123]len:6cap:6s1=s1[:cap(s1)]fmt.Println(s1,len(s1),再次追加数据(使用了变参)//原底层数组已经无法容纳新的数据,将重新分配内存,并拷贝原有数据//我们通过修改数组第一个元素来判断是否指向原数组////s3==[10000123456]len:9s3:=append(s2,[]int{4,5,6s3[0]=fmt.Println(s3,len(s3),slices3//s1==[000123]len:6//s2==[000123]len:6cap:6fmt.Println(s1,len(s1),cap(s1))fmt.Println(s2,len(s2),}输出[0[000]3[000123]6[000123]6[10000123456]9[000123]6[000123]6funcfunctest1(nint){datas:=make([]int,0,fori:=0;i<n;{datas=append(datas,}return}functest2(nint){datas:=make([]int,fori:=0;i<n;{datas[i]=}return}funcmain()//datas:=数组操作。test1append每次循环都会创建新的slice对象,累加起来的消耗并不小。funcmain()s1:=[]int{0,1,2,3,4,5,6,7,8,9s2:=make([]int,3,varnn=copy(s2,fmt.Println(n,s2,len(s2),n3。不同数组上拷贝。s2.len3,只能拷3个元//[012],len:3,s3:=s3[45]。s3和s1指向同一个底层数组n=copy(s3,fmt.Println(n,s1,//n=2。同一数组上拷贝,且存在区域//[0123126789][1}输出33[012]32[0123126789][1类型,类似Pythondict,不保证Key/Value存放顺序。Key必须是支持比较运算符(==、!=)number、string、pointer、array、struct、interface接口实现类型必须支持比较运算符),不能是function、map、slice。map查找操作比线性搜索快很多,但比起用序号array、slice,大约慢100x左右。绝大多数时候,其操作性能要略好于PythonDict、C++Map。funcfunctest(d{d["x"]=}funcmain()vard=map[string]int{"a":1,"b":2d2:=map[int]string{1:"a",2:"b"d3:=make(map[string]string)d3["name"]="Jack"fmt.Println(d3,len(d3))}输出map[a:1map[a:1b:2x:100]map[1:a2:b]map[name:Jack]1typetypeUser{Name}funcmain()a:=[2]int{0,b:=[2]int{0,d:=map[[2]int]string{a:"ssss"}fmt.Println(d,d[b])u:=User{"User1"}u2:=ud2:=map[User]string{u:"xxxx"}fmt.Println(d2,d2[u2])}输出map[[0map[[01]:ssss]map[{User1}:xxxx]typetypeUser{Name}funcmain()i:=d:=map[*int]struct{x,yfloat64}{&i:{1.0,2.0}fmt.Println(d,d[&i],d2:=map[string]interface{}{"a":1,"b":User{"user1"}}fmt.Println(d2,d2["b"].(User).Name)}输出map[0x42132018:{1map[0x42132018:{12}]{12}map[a:1b:{user1}]需要时,map会自动扩张容量。funcfuncmain()vard=map[string]int{"a":1,"b":2v,ok:=fmt.Println(v,keyb存在,v["b"okv=keyc不存在,v0keyokidiomd["c"]=delete(d,//删除。删除不存在的key,不 错误}输出220map[a:1c:3map[a:1funcfuncmain()d:=map[string]int{"a":1,"b":2fork,v:=ranged{println(k,"=",v)}获取key,fork:=range{println(k,"=",//仅获取}typetypeUser{IdintNamestring}funcmain()users:=make(map[string]User)users["a"]=User{1,"user1"}fmt.Println(users,//users["a"].Name="Jack"u:=users["a"]u.Name=users["a"]=//Error:cannotassignto}输出map[a:{1map[a:{1user1}]map[a:{1typetypeUser{IdintNamestring}funcmain()u:=User{100,"Tom"m:=map[int]*User{1:&u}fmt.Println(m,*m[1])m[1].Name="Jack"}输出map[1:0x42114b40]map[1:0x42114b40]{100map[1:0x42114b40]{100funcfuncmain()d:=map[string]int{"b":2,"c":3,"e":5fork,v:=range{println(k,ifk=="b"{delete(d,k)ifk=="c"{d["a"]=1}}ccbemap[a:1c:3第4章定定义结构很简单,但只有大写字母开头的成员才能在包外被(public,Go以开头大写字母作为typetypeUser{IdintNamestring}funcmain()user1:=User{1,"Tom"}user2:=User{Name:"Jack"}println(user2.Id,}输出110typetypeNodestruct Next*Node}funcmain():=&Node{Value::=&Node{Value:"b",Next:fmt.Printf("%#v\n",a)fmt.Printf("%#v\n",}输出&main.Node{_:0,&main.Node{_:0,Value:"a",&main.Node{_:0,Value:"b", {namestring contactcontact{phonestringaddressstringpostcodestring}}funcmain()vard=structname }{"user1",10,d2{age:10,}d2.contact.phone="d2.contact.address=d2.contact.postcode="//fmt.Println(d,}funcfunctest()d:={xstringyint"a":{"a10","b":{"b20",}}初始u1:=User{1,"Tom"u2:=User{Id:2,Name:"Jack"p1:=&User{1,"Tom"}p2:=&User{}

性用 性用法,相当于new(User)typetypeUser{IdintNamestring}funcmain()u:=&User{100,"Tom"}println(u.Id,u.Name)u.Id=println(u.Id,}输出100100200typetypeUser{IdintNamestring}funcmain()u:=User{100,"Tom"}println(u.Id,u.Name)varu2*User=*u2=println(u2.Id,}println(User{"a"}== 字Go对""成员运算符做了特殊处理,使得我们可以直接和设置字段成员。但在初始化成员typetypeUser{IdintNamestring}typetypeManager{Group}funcmain()m:=Manager{User{1,"Jack"},"IT"}println(m.Id,m.Name,m.Group)m.Name=println(m.Id,m.Name,}输出11Jack1TomtypetypeUser{IdintNamestring}typeManager{Group}typeCXO{ManagerTitlestring}funcmain()ceoCXO{Manager{User{100,猪头三"Boardofdirectors""CEO"fmt.Println(ceo,ceo.Id,ceo.Name,ceo.Group,ceo.Title)}输出{{{100猪头三}Boardofdirectors}CEO}100猪头三Boardofdirectors typetypeUser{IdintNamestring}typeManager{Group}funcmain()m:=Manager{User:User{1,"Jack"},Group:"IT",int:100,string:" o!"}println(m.Id,m.Name,m.Group,,m.string)m.Name="Tom"=200m.string="World!"println(m.Id,m.Name,m.Group,,}输出11JackIT1TomIT200typetypeD1{x}typeDatastructx}funcmain()d:=Data{D1{10},20println(d.x,d.x=d.D1.x=println(d.x,}输出2020200typetypeD1{x}typeD2structxx}typeData{D1}funcmain()d:=Data{D1{10},D2{20}}输出main.go:24:main.go:24:ambiguousDOTreferencemake:***[_go_.6]Errorfuncfuncmain()d:=Data{D1{10},D2{20}println(d.D1.x,}输出10 typetypeData{D1x}funcmain()d:=Data{D1{10},D2{20},30println(d.x,d.D1.x,}输出3010 量子类对象的行为,称为多态,是OOP的重要特征之一)typetypeUser{IdintNamestring}typeManagerstruct}funcmain()m:=Manager{User:User{1,"Tom"},Group:"IT"//varuUser=varuUser=//Error:cannotusem(typeManager)astypeUserin//valuefmt.Println(m,}typetypeUser{IdintNamestring}typeManager{Group}funcmain()m:=Manager{User:&User{1,"Tom"},Group:"IT"注意初始化字段fmt.Println(m,m.Id,//就算是指针 成员也木有压力}输出{IT0x42114b40}1 方PythonMethodReceivertypetypeUser{IdintNamestring}func(this*User){println(this.Id,}funcfunc(thisUser){println(this.Id,}funcmain()u:=&User{1,"Jack"}}typetypeUser{Name}func(User){)省略Receiver的参数func(this*User){println("Test2:",因methodset的缘故,名字不能Receiver类型不同也不行否则导"methodredeclared"编译错误funcmain()u:=User{"Tom"}p:=&u自动转换,相当于(&u).Test2()自动转换,相当于(*p).Test()}输出Test2:typetypeMyInttypeMySliceintMyInt重新定义"func(thisMyInt){fmt.Printf("MyInt=%v\n",}func(thisMySlice){fmt.Printf("MySlice=%v\n",}funcmain()i:=MyInt(10)s:=MySlice{100,200}MethodValuesvs.Method法。也正因为如此,我们可以将方法"还原"成函数。instance.method(args)->(type).func(instance, MethodExpression函数将Receiver作为第一个显式参数,调用时需额外传递。typetypeUser{Name}func(thisUser)Test(xfunc(this*User)Test2(sstring)funcmain()u:=/*===MethodValue======*/varf1func(int)=u.TestReceivervarf2func(string)=/*===MethodExpression======User.Test(u,123)Receivervarf3func(User,int)=f3(u,ReceiverReceivervarf4func(*User,string)=f4(&u,}typetypeUser{Name}func(thisUser){}funcmain()u:=User{"Tom"}f:=u.Test//为f专门准备了一个u.Name=对u的修改不会影响f的Receiverf使用的是自带的Receiver,和u没啥关系}输出typetypeUserstructName}}func(thisUser){fmt.Printf("V:%p,%v\n",&this,}func(this*User){fmt.Printf("P:%p,%v\n",this,}funcmain()u:=fmt.Printf("u:%p,%v\n",&u,UserTestPointer Error:User.TestPointerundefined(typeUserhasnomethod//*UserTestValue、TestPointerTestValueReceiverPointer//m,_:=输出u:u:0x210196150,{Tom}V:0x210196190,{Tom}P:0x210196150,{TestValuefunc(*main.User)<func(*main.User)Value>typetypeUserstruct{Namestring}func(User)Test() func(*User)Test2()funcmain()varu*User不管怎样,编译器调用funcTest(User)总归要有一个合法的UserReceiver实例 runtimeerror:invalidmemoryaddressornilpointer//}修改不会影响到Caller。funcfunc(this{this.Id=200;this.Name="Tom"println(&this,this.Id,}funcmain()u:=User{1,"Jack"}println(&u,u.Id,}输出0x442085f780x442085f782000x442085f901到GCHeap上。如果对象很"小",显然要比在栈上进行值拷贝"耗费"。时,同样有隐藏规是基于这种隐藏规则,我们很容易实现override效果。typetypeUser{IdintNamestring}typeManager{Group}func(this*User)Test()println("UserTest:",this.Id,}func(thisUser)ToString()stringreturnfmt.Sprintf("UserToString:[%d]%s",this.Id,}funcfunc(thisManager)Test()println("ManagerTest:",this.Id,}funcmain()m:=&Manager{User{1,"Tom"},}输出ManagerManagerTest:1UserToString:[1]typetypeUser{IdintNamestring}typeManager{Groupstring}funcmain()m:=Manager{User:User{1,"Tom"},Group:"IT"varp*User=println(p.Id,//并不是真的多态,只不过 的字段而已}typetypeUser{IdintNamestring}typeManager{Groupstring}放在第二个位置,offset0,使其和外Manager内存地址不同func(this*User)Test()fmt.Printf("Testthisaddress=%p\n",}funcmain()m:=&Manager{User:User{1,"Tom"},Group:"IT"fmt.Printf("m.address=%p\n",m)fmt.Printf("m.User.addressfmt.Printf("m.address=%p\n",m)fmt.Printf("m.User.address=%p\n",&m.User)}输出m.address=0x421016c0m.User.addressm.address=0x421016c0m.User.address=0x421016d0Testthisaddress=typetypeA{x}typeB{x}func(this*A){println("A:",A.x,因为this*A类型根本不包括B的成员func(this*B){println("B:",//funcmain()o:=B{x:}输出B:B:A:内存布packagepackageimport)typeUserstructIdIdName}typeManager{Groupstring}funcmain()m:=Manager{User:User{1,"Tom"},Group:"IT"fmt.Printf("malignof=%d\n",unsafe.Alignof(m))fmt.Printf("maddress=%p\n",&m)fmt.Printf("msize=%d\n",fmt.Printf("m.Groupaddress=%p\n",&m.Group)fmt.Printf("m.Groupoffset=%d\n",unsafe.Offsetof(m.Group))fmt.Printf("m.Groupsize=%d\n",unsafe.Sizeof(m.Group))fmt.Printf("m.Useraddress=%p\n",&m.User)fmt.Printf("m.Useroffset=%d\n",unsafe.Offsetof(m.User))fmt.Printf("m.Usersize=%d\n",unsafe.Sizeof(m.User))fmt.Printf("User.Idaddress=%p\n",fmt.Printf("User.Idoffset=%d\n",unsafe.Offsetof(m.User.Id))fmt.Printf("User.Idsize=%d\n",unsafe.Sizeof(m.User.Id))fmt.Printf("User.Nameaddress=%p\n",fmt.Printf("User.Nameoffset=%d\n",unsafe.Offsetof(m.User.Name))fmt.Printf("User.Namesize=%d\n",unsafe.Sizeof(m.User.Name))}输出malignof=maddress=0x421016c0msize=40m.Groupaddress=0x421016c0m.Groupoffset=0m.Groupsize=m.Useraddress=0x421016d0m.Useroffset=16m.Usersize=User.Idaddress=0x421016d0User.Idoffset=0User.Idsize=User.Nameaddress=0x421016d8User.Nameoffset=8User.Namesize=16

内容长度20,按8字节对齐后为24字packagepackageimport)typeUser{Namestring"姓名"Ageint" }funcmain()u:=User{"Tom",t:=reflect.TypeOf(u)v:=reflect.ValueOf(u)fori:=0;i<t.NumField();{f:=fmt.Printf("%s(%s=%v)\n",f.Tag,f.Name,}}输出(Name(Name=(Age=第5"实现"了该接口,无需显式在该类型上添加接口。此种方式,又被称作DuckType。接口定typetypeTester{}typetypeReader{}typeWriter{}typeReadWriter{Reader}typeReadWriteTeststruct}func(*ReadWriteTest){}func(*ReadWriteTest){}funcmain()t:=varrwReadWriter=}typetypeTester{}typeMyTeststruct}func(this{}typeUser{Idint}funcmain()u:=User{100,"Jack",nil}u.Tester=new(MyTest)}输出{100{100JacktypetypeUser{Name}func(this*User)String()stringreturnfmt.Sprintf("Name:%s",}typeData{s{String()} 接口类型成funcfuncmain()vari{String()d:=Data{&User{"Jack"}}}执行机struct{Itab*void*struct{InterfaceType*swtchcom/interfacescom/group/golang-nuts/browsethread/thread/typetypeUser{IdintNamestring}typeTester{}funcfunc(thisUser)Test()funcmain()u:=User{1,"Tom"}i:=Tester(u)u.Id=u.Name=//fmt.Println(u,//虽然接口内 品未受到影//i.(User).Name=无法操作cannotassignto要是指针就没问题了。i.(*User).Name//cannottaketheaddressof}输出{100Jack}{1 funcfuncmain()varainterface{}println(unsafe.Sizeof(a),a==nil)}输出16, funcfuncmain()varainterface{}=println(a==//type:nil,value:varp*int=varbinterface{}=println(b==//type:*int,value:}输出itab依据data类型创建,了接口动态调用的元数据信息,其中包括data类型所有符合接口签名的方法地址列表。用接口对象调用方法时,就从itab中查找所对应的方法,并*data(指针)作为receiver参数传递给该方法,完成实际目标方法调用。编译itab时,会T*T方法(methodsets),并从中获取接口实现方法的地址。接口调用不会做receiver自动转换,目标方法必须在接口实现方法集中。MethodMethodAtypemayhaveamethodsetassociatedwithit(Interfacetypes,Methoddeclarations).Themethodsetofaninterfacetypeisitsinterface.ThemethodsetofanyothernamedtypeTconsistsofallmethodswithtypeT.Themethodsetofthecorrespondingpointertype*Tisthesetofallmethodswithreceiver*TorTis,italsocontainsthemethodsetofT).Anyothertypehasanemptymethodset.Inamethodset,musthaveauniquevalue-copypointer-interface,T*Tmethodvalue-interface*T方法是无法保证合法操作WhyWhydoTand*ThavedifferentmethodFromtheGoThemethodsetofanyothernamedtypeTconsistsofallmethodswithreceivertypeT.Themethodsetofthecorrespondingpointertype*Tisthesetofallmethodswithreceiver*TorT(thatis,italsocontainsthemethodsetofT).Ifaninterfacevaluecontainsapointer*T,amethodcallcanobtainavaluebydereferencingthepointer,butifaninterfacevaluecontainsavalueT,thereisnousefulwayforamethodcalltoobtainapointer.Evenincaseswherethecompilercouldtaketheaddressofavaluetopasstothemethod,ifthemethodmodifiesthevaluethechangeswillbelostinthecaller.Asacommonexample,thiscode:varbufbytes.Bufferio.Cop

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论