医学类的网站做Google,课程网站建设毕业设计,餐厅网络推广方案,上海市公司名称大全1.认识Golang代码特性
package main //1.包含main函数的文件就是一个main包--当前程序的包名// import fmt
// import time
import(fmttime
)//3.同时包含多个包 4.强制代码风格:函数的 { 一定和函数名在同一行#xff0c;否…1.认识Golang代码特性
package main //1.包含main函数的文件就是一个main包--当前程序的包名// import fmt
// import time
import(fmttime
)//3.同时包含多个包 4.强制代码风格:函数的 { 一定和函数名在同一行否则会出现语法错误//main函数
func main() {fmt.Println(hello Go!)// fmt.Println(hello Go!); 2.加不加分号都可以建议不加分号time.Sleep(1 * time.Second)
}
2.Golang变量声明的四种方式
package mainimport (fmt
)func main() {//方法一声明一个变量不初始化默认是0var a intfmt.Println(a ,a)fmt.Printf(type of a %T\n,a)//方法二声明一个变量初始化var b int 100fmt.Println(b ,b)fmt.Printf(type of b %T\n,b)var bb string abcdfmt.Printf(bb %s,type of bb %T\n,bb,bb)//方法三在初始化时可以省去数据类型通过值自动匹配当前的变量的数据类型var c 100fmt.Println(c ,c)fmt.Printf(type of c %T\n,c)var cc abcdfmt.Printf(cc %s,type of cc %T\n,cc,cc)//方法四(常用的方法)省去var的关键字直接:自动匹配;在声明的变量是全局变量时方法四是不可用的会报错e : 100fmt.Println(e ,e)fmt.Printf(type of e %T\n,e)ee : abcdfmt.Printf(ee %s,type of ee %T\n,ee,ee)eee : 3.14fmt.Printf(eee %s,type of eee %T\n,eee,eee)//声明多个变量var xx,yy int 100,200 //相同数据类型fmt.Println(xx ,xx, yy ,yy)var mm,nn 100,abcd //不同数据类型fmt.Println(mm ,mm, nn ,nn)//多行的多变量声明var (vv int 100jj bool true)fmt.Println(vv ,vv, jj ,jj)
}
3.常量与iota
package main//const 来定义枚举类型
const (//可以在const()添加一个关键字 iota每行的iota都会累加1第一行的iota的默认值是0BEIJING iota //iota 0SHANGHAI //iota 1SHENZHEN //iota 2
)
//iota只能出现在const的括号中
const (a,b iota1,iota2// 01,02c,d // 11,12e,f // 21,22g,h iota*2,iota*3// 3*2,3*3i,k // 4*2,4*3
)
func main()
{//常量-具有只读属性const length int 10fmt.Println(length ,length)length 100 //报错-常量不可更改
}
4.Golang多返回值的三种写法
package main
import fmtfunc fool(a string,b int) int {fmt.Println(a ,a)fmt.Println(b ,b)c : 100return c
}//1.返回多个返回值-匿名
func foo2(a string,b int) (int,int) {fmt.Println(a ,a)fmt.Println(b ,b)return 666,777
}//2.返回多个返回值-有形参名称
func foo3(a string,b int) (r1 int,r2 int) {fmt.Println(------------foo3-----------)fmt.Println(a ,a)fmt.Println(b ,b)r1 1000r2 2000return r1,r2//return; 方法3--也可以返回r1,r2
}func main() {c : fool(abc,555)fmt.Println(c ,c)ret1,ret2 : foo2(bfr,666)fmt.Println(ret1 ,ret1,ret2 ,ret2)ret3,ret4 : foo3(grx,777)fmt.Println(ret3 ,ret3,ret4 ,ret4)
}
5.init函数与import导包 递归式导包直到最后一个包没有依赖包-加载该包全局的常量变量-执行init函数 主程序开始之前加载一些配置文件、加载一些数据库的内容、基本环境变量的初始化
package mainimport(GolangStudy/Golang_5/lib1GolangStudy/Golang_5/lib2
)func main(){lib1.LibTest()lib2.LibTest()
}
package lib1import fmt//API接口
func LibTest() {fmt.Println(Lib1Test.....)
}
//init初始化函数
func init() {fmt.Println(Lib1init.....)
}
package lib2import fmt//API接口--大写首字母表示对外开放该接口
func LibTest() {fmt.Println(Lib2Test.....)
}
//init初始化函数
func init() {fmt.Println(Lib2init.....)
}
运行结果
三种导包的方式
//三种导包的方式
import(_ GolangStudy/Golang_5/lib1 //_表示匿名可以在不使用该包但是可以调用它的init函数-无法使用当钱包的方法//mylib GolangStudy/Golang_5/lib2 //给包起别名mylib. GolangStudy/Golang_5/lib2 // . 表示将该包直接导入main包直接使用
)func main(){//lib1.LibTest()//lib2.LibTest()//mylib.LibTest()LibTest()//同名方法容易导致歧义
}
6.Golang中指针的使用
package main
import fmtfunc swap(pa *int, pb *int) {var tem int;tem *pa *pa *pb*pb tem
}func main() {var a int 10var b int 20swap(a,b)fmt.Println(a ,a,b ,b)var p *intp afmt.Println(p ,p)var pp **int pfmt.Println(pp ,pp)
}
7.Golang中的defer语句
package main
import fmtfunc main(){//写入defer关键字--类似C中的析构函数--出它作用域时会调用defer fmt.Println(main end1)//先入栈defer fmt.Println(main end2)//再入栈fmt.Println(main run1)fmt.Println(main run2)
}
输出结果
defer和return的执行顺序
func deferFunc() int{fmt.Println(defer func called...)return 0
}
func returnFunc() int{fmt.Println(return func called...)return 0
}
func rad() int {defer deferFunc()return returnFunc()
}
func main() {rad()
}
输出结果 return比defer先执行
8.Golang中的数组
—静态数组 静态数组传参是值拷贝传参并且只能接收特定格式的数组确定元素类型与元素个数
package main
import fmt//值拷贝传参将实参数组拷贝给形参
func printArray(myArray [10]int) { //只能接收1、2即int[10]数据类型for index,value:range myArray {fmt.println(index, ,value)}
}
func printArray(myArray [4]int) { 只能接收3即int[4]数据类型for index,value:range myArray {fmt.println(index, ,value)}
}func main(){//固定长度的数组var myArray1 [10]intmyArray2 : [10]int{1,2,3,4}myArray3 : [4]int{1,2,3,4}//for i: 0; i10; ifor i:0; ilen(myArray1); i{fmt.println(myArray1[i])}for index,value:range myArray1 {fmt.println(index, ,value)}//查看数组的数据类型fmt.printf(myArray1 types %T\n,myArray1)fmt.printf(myArray2 types %T\n,myArray2)fmt.printf(myArray3 types %T\n,myArray3)
}
—动态数组(slice切片)
package main
import fmt//动态数组具有传参上的优势
//传递的是当前数组的指针首地址引用传递
func printArray(myArray []int) {// _ 表示匿名的变量for _, value : range myArray {//不关心下标但必须用两个接收fmt.Println(value ,value)}myArray[0] 100
}func main() {myArray : []int{1,2,3,4} //动态数组,切片 slicefmt.Printf(myArray type is %T\n,myArray)//输出myArray type is []intprintArray(myArray)for _, value : range myArray {fmt.Println(value ,value)}
}
—四种声明一个切片的方式
func main () {//声明slice是一个切片并且初始化默认值是123长度len是3slice : []int{1,2,3}//声明slice1是一个切片但没有给它分配空间var slice1 []int //此时长度就是0slice1 make([]int,3)//通过make给slice1分配空间默认值是0//声明slice2是一个切片同时通过make给slice2分配空间默认值是0var slice2 []int make([]int,3)//声明slice3是一个切片,同时分配空间通过:推导出slice是一个切片slice : make([]int,3)fmt.Printf(len %d,slice %v\n,len(slice1),slice1)//判断一个slice是否为0if slice nil {fmt.printf(slice是一个空切片)}else{fmt.printf(slice不是一个空切片)}
}
—切片容量的追加
func main () {var numbers make([]int,3,5)//开辟五个空间只初始化3个为0fmt.Printf(len %d,cap %d,numbers %v\n,len(numbers),cap(numbers),numbers)//向numbers切片追加一个1numbers append(numbers,1)fmt.Printf(len %d,cap %d,numbers %v\n,len(numbers),cap(numbers),numbers)numbers append(numbers,2)fmt.Printf(len %d,cap %d,numbers %v\n,len(numbers),cap(numbers),numbers)numbers append(numbers,3)//会进行2倍扩容fmt.Printf(len %d,cap %d,numbers %v\n,len(numbers),cap(numbers),numbers)var numbers2 make([]int,3)//开辟三个空间并全部初始化为0fmt.Printf(len %d,cap %d,numbers2 %v\n,len(numbers2),cap(numbers2),numbers2)numbers2 append(numbers2,1)//会进行2倍扩容fmt.Printf(len %d,cap %d,numbers2 %v\n,len(numbers2),cap(numbers2),numbers2)
} 输出结果
—切片的截取
func main () {s : []int{1,2,3} //len3,cap3//[0,2)s1 : s[0:2] //取1和2前面省略表示从第0个开始取后面省略表示取到最后一个fmt.Println(s1)s1[0] 100fmt.Println(s1) //s1此时也指向s的第一个相当于浅拷贝fmt.Println(s)//copy深拷贝将底层数组的slice一起进行拷贝s2 : make([]int,2) //s2 [0,0,0]copy(s2,s1)fmt.Println(s2) //可以先将s切片成s1再进行深拷贝给s2就可以分离
}
9.Golang中基于哈希的Map
—Map的三种声明定义方式
func main() {//第一种声明方式var myMap1 map[string]string //仅仅是声明没有实际的空间,并不能被使用if myMap1 nil {fmt.Println(myMap1是一个空map)}myMap1 make(map[string]string,10) //用make给Map开辟十个键值对的空间myMap1[one] javamyMap1[two] CmyMap1[three] python//...当插入十个之后也会二倍扩容fmt.Println(myMap1)//打印出来是无序的//第二种声明方式myMap2 : make(map[int]string)myMap2[1] javamyMap2[2] CmyMap2[3] pythonfmt.Println(myMap2)//第三种声明方式myMap3 : map[int]string {4 : java,5 : C,6 : python,}fmt.Println(myMap3)
}
—Map的基本使用
func printMap(cityMap map[string]string) {for key,value : range cityMap {fmt.Printf(key %s ,key)fmt.Printf(value %s\n,value)}cityMap[one] golang
}//指向当前map内存结构体地址的指针cityMapfunc main() {cityMap : make(map[string]string,3)//添加cityMap[one] javacityMap[two] CcityMap[three] python//删除delete(cityMap,three)//修改cityMap[two] php//传参printMap(cityMap)//遍历for key,value : range cityMap {fmt.Printf(key %s ,key)fmt.Printf(value %s\n,value)}
}
//将一个map赋值给另一个时只能完成指针之间的浅拷贝只能通过make开辟一个Map进行遍历赋值
10.struct(类)的定义和使用
—struct类的定义
//声明一种行的数据类型是Int的一个别名
type myint int
type Book struct {title stringauth string
}func changeBook(book Book) {//传递book的一个副本book.auth 666
}
func changeBook2(book *Book) {//传递指向Book结构体的指针book.auth 777
}func main() {// var a myint 10// fmt.Printf(type %T,a)var book1 Bookbook1.title Golangbook1.auth zhang3fmt.Printf(book1 %v,book1)
}
—类的封装和方法的调用
//go语言中的类实际上是通过结构体来绑定方法
package main//方法名、类名如果首字母大写其它包也可以访问
type Hero struct {Name stringAd intLevel int
}//当前括号表示该方法绑定到了Hero结构体this表示调用对象谁调用该方法this就指哪个对象
func (this Hero) GetName() string{return this.Name
}//this是当前调用对象的一个副本
func (this Hero) SetName(newName string) {this.Name newName
}
//此时this就是指向当前对象的指针就可以修改了
func (this *Hero) SetName(newName string) {this.Name newName
}func main() {//创建一个对象hero : Hero{Name: zhang3,Ad: 100,Level: 1}
}
—继承的基本语法
type Human struct {name stringsex string
}func (this *Human) Eat() {fmt.Println(human Eat().....)
}
func (this *Human) Walk() {fmt.Println(human Walk().....)
}type SuperMan struct {//Go中实际是以组合的形式实现继承Human //Superman继承了Human类的所有方法level int
}//重写(覆盖)父类方法
func (this *SuperMan) Eat() {fmt.Println(SuperMan Eat().....)
}//子类的新方法
func (this *SuperMan) Fly() {fmt.Println(SuperMan Fly().....)
}func main() {h : Human{zhang3,female}h.Eat()h.Walks : SuperMan{Human{li4,female},88}// var s SuperMan// s.name li4//...s.Walk() //子类调用父类的方法s.Eat() //子类调用子类重写的方法s.Fly() //子类调用子类的新方法
}
—interface实现多态
package main
//面向对象的多态定义一个接口完成多态的现象;接口定义抽象方法子类去继承实现重写这个方法//interface本质上是一个指针指向当前类型包含的函数列表
type AnimalIF interface {Sleep()GetColor() string //获取动物的颜色GetType() string //获取动物的类型
}//具体的值--要继承AnimalIF interface只需要将他的三个方法实现不需要显式继承
type Cat struct {color string //猫的颜色
}func (this *Cat) Sleep() {fmt.Println(cat is sleep)
}func (this *Cat) GetColor() string {return this.color
}func (this *Cat) GetType() string {return cat
}//具体的值--狗
type Dog struct {color string
}func (this *Dog) Sleep() {fmt.Println(Dog is sleep)
}func (this *Dog) GetColor() string {return this.color
}func (this *Dog) GetType() string {return Dog
}func showAnimal(animal AnimalIF)//调用该函数形参为父类指针实参为子类对象实现多态
{animal.Sleep()
}func main() {// var animal AnimalIF //接口的数据类型相当于定义了一个父类指针// animal Cat(green) //让父类的指针指向一个子类对象// animal.Sleep() //指向子类对象的父类指针调用子类方法实现多态cat : Cat(green)dog : Dog(yellow)showAnimal()
}
—interface{}空接口万能类型
//interface{} 空接口万能类型-》可以引用任意数据类型
package mainimport fmtfunc myFunc(arg interface{}) { //可以传任意类型的实参fmt.Println(myFunc is called..)fmt.Println(arg)//类型断言value,ok : arg.(string) //value是数据值ok是errorif !ok {fmt.Println(arg is not a string)}else{fmt.Println(arg is a string)}fmt.Println(value)
}type Book struct {auth string
}func main() {book : Book{Golang}myFunc(book)myFunc(abcd)myFunc(888)myFunc(23.45)
}
11.Golang中反射的概念
—接口type interface { }的类型 Golang中一个变量包含一个pair即type和value对。 type分为static type(在编译时就确定并且不会改变)和concrete type(在运行时确定并且会改变)。
var i int // static type 为 int;
var i interface{} // pair()
i 18 // concrete type 为 int
i Go编程时光 // concrete type 变为 string
type Reader interface {ReadBook()
}type Writer interface {WriteBook()
}//具体类型
type Book struct {
}func (this *Book) ReadBook() {fmt.Println(Read a book.)
}func (this *Book) WriteBook() {fmt.Println(Write a book.)
}func main() {b : Book{} //type:*Book value:0xc000012028var r Reader //concrete type:nil,static typeReader value:nilr b //concrete type:Book*,static type Reader value:0xc000012028r.ReadBook() //Reader - Book* 多态var w Writer //concrete type:nil,static typeWriter value:nilw r.(Writer)//类型断言,检查r是否实现了Writer并将Book*给ww.WriteBook()
}
—reflect.ValueOf 和 reflect.TypeOf
package mainimport fmt
import reflecttype User struct {Id int//一个filedName string//第二个filedAge int //第三个filed
}func (this *User) Call() {fmt.Println(User is called ...)fmt.Println(%v\n,this)
}func main() {user : User{1,bfr,18}DoF(user)
}func DoF(input interface{}) {//获取input的typeinputType : reflect.TypeOf(input)fmt.Println(inputType :,inputType.Name())//?直接打印出当前类型的名称//获取input的valueinputValue : reflect.ValueOf(input)fmt.Println(inputValue :,inputValue)//通过type获取里面重要字段//通过inputType可以获取NumFiled进行遍历就能得到每个filedfor i : 0;i inputType.NumField(); i {field : inputType.Field(i)value : inputValue.Field(i).Interface()//?获取字段的值fmt.Printf(%s: %v %v\n,field.Name,field.Type,value)//ID,int,1}//通过Type获取里面的方法调用for i:0; iinputType.NumMethod(); i { //遍历User有多少个方法m : inputType.Method(i)fmt.Printf(%s: %v\n,m.Name,m.Type)}
} 12.结构体标签
package main
import fmt
import reflect//在不同包中有不同的解释说明
type resume struct {Name string info:name doc:我的名字Sex string info:sex
}func findTag(str interface{}) {t : reflect.TypeOf(str).Elem()//Elem当前结构体的全部元素for i : 0; i t.NumField(); i {taginfo : t.Field(i).Tag.Get(info)tagdoc : t.Field(i).Tag.Get(doc)fmt.Println(info: ,taginfo, dac:,tagdoc)}
}func main() {var res resumefindTag(res)
}
//结构体标签-key已知value未知
type Movie struct {Title string json:title //在json中显示的字段Year int json:yearPrice int json:priceActors []string json:actors
}func main() {movie : Movie{喜剧之王,2000,10,[]string{xingye,zbz}}//编码的过程 将结构体-jsonjsonStr,err : json.Marshal(movie)//Marshal可以将结构体转化为json格式if err ! nil {fmt.Println(json marshal error,err)}else{fmt.Printf(josnStr %s\n,jsonStr)}//解码的过程 json-结构体myMovie : Movie{}err json.Unmarshal(jsonStr,myMovie)//将json字符串解析给myMovie结构体if err ! nil {fmt.Println(json unmarshal error,err)return}
}
13.Golang中的协程:goroutine
—协程的演变发展
—单进程的操作系统只能顺序执行任务一旦某个任务阻塞其它任务都不能处理。 —多进程/多线程解决了CPU调度器进行轮询调度切换进程/线程 当某个时间片到了就会切换。但是进程/线程间切换具有成本一旦数量过大CPU的使用效率就会大大降低。进程占4GB左右,线程占用4MB左右也有高内存占用的弊端。 —将一个线程拆分一半在用户层面供用户调用(协程:co-routine)一半在内核层供CPU调度。 —N : 1如果有一个协程阻塞那它的下一个协程就会受到影响。操作系统感知不到用户级协程的存在无法将阻塞的协程与线程分离线程资源被完全占用 —M : N利用多核一个CPU绑定多个线程解决了某个协程阻塞影响其它协程的问题通过优化写成调度器优化效率CPU不做调度。
—Golang对协程的处理 co-routine - goroutine将占用内存优化到KB单位(可以大量生产)(可以灵活调度)。 —通过优化调度器实现灵活调度
package mainimport fmt
import timefunc newTask() {i:0for { ifmt.Printf(new Goroutine : i %d\n,i) time.Sleep(1 * time.Second)}
}func main() {//创建一个go程 去执行newTask()流程go newTask()time.Sleep(10*time.Second)fmt.Println(main goroutine exit)// i:0// for { //死循环main// i// fmt.Printf(main goruntine: i %d\n,i)// time.Sleep(1*time.Second)// }
}
package mainimport fmt
import time
import runtimefunc main() {//调匿名无参goroutinego func() {//匿名方法直接用Go承载一个形参为空返回值为空的一个函数defer fmt.Println(A.defer)func() {//仅仅是函数定义defer fmt.Println(B.defer)//return runtime.Goexit()fmt.Println(B)}()fmt.Println(A)}()//调用//调匿名有参goroutinego func(a int,b int) bool { //并不是阻塞操作是一个异步操作不能拿到返回值fmt.Println(a ,a, b ,b)return true}(10,20)time.Sleep(1*time.Second)
} 14.channel-go语言中协程间通信的机制
—构成死锁 1.无缓存channel、只写不读或只读不写、导致主线程阻塞。 2.有缓存channel、已满只写不读或为空只读不写、导致主线程阻塞。
package main
import fmt
//import timefunc main() {c : make(chan int,3)//带有缓冲的channelfmt.Println(len(c) ,len(c), cap(c) ,cap(c))go func() {defer fmt.Println(子go程结束)for i:0;i6;i{c - ifmt.Println(running...:,i ,i, len(c) ,len(c), cap(c) ,cap(c))}}()//time.Sleep(2 * time.Second)// for i:0;i2;i {// num : -c //从c中接收数据并赋值给num// fmt.Println(num ,num)// }fmt.Println(main 结束)
}
—close关闭channel 关闭channel后无法向channel再发送数据(再发会引发 panic 错误后导致接收立即返回零值) 关闭channel后仍旧具有缓存等读端读完了才会返回。 简单var声明一个channel数据类型没有进行make称为nil channel。无论收发都会阻塞。
package main
import fmt
func main() {c : make(chan int)go func() {for i:0;i5;i {c - i}//close可以关闭一个channelclose(c)}()for {//oktrue表示channel没有关闭if data,ok : -c; ok { //原子性操作确保通道接收与状态检查在同一个代码块中完成fmt.Println(data)}else{break}}fmt.Println(Main Finished..)
}
—channel 和 range 尝试从c中读数据range会阻塞等待这个结果c中有数据range就会返回并进入本轮for循环没有数据就会阻塞
//可以使用range来迭代不断操作channel
for data : range c { fmt.Println(data)}
—channel 和 select 单流体下的一个go只能监视一个channel状态阻塞监听select可以解决一个go监听多个channel状态如果某个channel可读或可写它就会立刻返回。一般会循环进行select监控多个channel。
package mainimport fmtfunc fibo(c,quit chan int){x,y : 1,1 //1,1-1; 1,2-1; for{select{case c - x: //只要func可读这边就可写//如果c可写则该case就会进来t : xx yy tycase -quit: //只要quit被写入这边就可读就退出fmt.Println(quit)return}}
}func main() {c : make(chan int)quit : make(chan int)go func() {for i : 0; i 6; i{fmt.Println(-c)//读c}quit - 0 //循环结束退出}()//main gofibo(c,quit)
}