流行度排行
https://github.com/speedwheel/awesome-go-web-frameworks/blob/master/README.md#popularity
beego
https://beego.me/products
echo
https://echo.labstack.com/
gin go社区文档
https://learnku.com/docs/gin-gonic/2019
看云gin文档
https://www.kancloud.cn/shuangdeyu/gin_book/949418
gin快速使用
https://www.jianshu.com/p/98965b3ff638
gin-admin-vue
https://www.gin-vue-admin.com/docs/gorm
官网
https://golang.org/dl/
中文官网
https://go-zh.org/pkg/
go常用库
https://github.com/jobbole/awesome-go-cn
查看版本号
go version
查看env
go env
==拉不下来包==
export GOPATH=/usr/local/go/binexport goproxy=https://goproxy.ioexport PATH=$PATH:$GOPATHexport GO111MODulE=on
开启module
go env -w GO111MODulE=on
设置代理
微服务框架go env -w goproxy=https://goproxy.io,direct
go-kit
go micro
go-zero
常用网址go基础知识
go基础知识v1
go基础知识v2---micro
菜鸟GO
文档和技术论坛
gomod 详细使用
go官网库
==go官方pkg中文==
github对pgk的使用例子
go mod使用基本数据类型字符串 *** 作本地gorm struct生成本地struct生成https://github.com/xxjwxc/gormt.git
https://github.com/hantmac/fuckdb.git
1 使用docker-composer方式启动2 遇到docker容器不能链接本地MysqL的时候 在本地MysqLGRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;FLUSH PRIVILEGES
struct 生成go get -u github.com/gohouse/converter
err := converter.Newtable2Struct(). SavePath("./model.go"). Dsn("root:root@tcp(127.0.0.1:3306)/foroo_beta_shopify?charset=utf8"). TagKey("db"). EnableJsonTag(true). table("fr_store"). Run()fmt.Println(err)return
基础变量或者方法使用小写相当于protect 首字母大写 相当于public
使用+来拼接字符串
变量声明 var age int;
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
可以将 var f string = "Runoob" 简写为 f := "Runoob":
函数外的每个语句都必须以关键字开始(var、const、func等)
:=不能使用在函数外。
_多用于占位,表示忽略值。import _ "./hello" 用_占位只会执行导入包内的init,其他方法都不能调用
iota是go语言的常量计数器,只能在常量的表达式中使用
strconv.Itoa(97) 将一个数字转成字符串类型 string(97)go自带的会把数字转换成对应的ascii码
const ( n1 = iota //0 n2 //1 n3 //2 n4 //3 )
map、slice、chan、指针、interface默认以引用的方式传递。
互斥锁 var lock sync.Mutex
var x int64var wg sync.WaitGroupvar lock sync.Mutexfunc add() { for i := 0; i < 5000; i++ { lock.Lock() // 加锁 x = x + 1 lock.Unlock() // 解锁 } wg.Done()}func main() { wg.Add(2) go add() go add() wg.Wait() fmt.Println(x)}
读写互斥锁 需要注意的是读写锁非常适合读多写少的场景,如果读和写的 *** 作差别不大,读写锁的优势就发挥不出来。
var ( x int64 wg sync.WaitGroup lock sync.Mutex rwlock sync.RWMutex)func write() { // lock.Lock() // 加互斥锁 rwlock.Lock() // 加写锁 x = x + 1 time.Sleep(10 * time.Millisecond) // 假设读 *** 作耗时10毫秒 rwlock.Unlock() // 解写锁 // lock.Unlock() // 解互斥锁 wg.Done()}func read() { // lock.Lock() // 加互斥锁 rwlock.RLock() // 加读锁 time.Sleep(time.Millisecond) // 假设读 *** 作耗时1毫秒 rwlock.RUnlock() // 解读锁 // lock.Unlock() // 解互斥锁 wg.Done()}func main() { start := time.Now() for i := 0; i < 10; i++ { wg.Add(1) go write() } for i := 0; i < 1000; i++ { wg.Add(1) go read() } wg.Wait() end := time.Now() fmt.Println(end.Sub(start))}
sync.Once其实内部包含一个互斥锁和一个布尔值,互斥锁保证布尔值和数据的安全,而布尔值用来记录初始化是否完成。这样设计就能保证初始化 *** 作的时候是并发安全的并且初始化 *** 作也不会被执行多次。
var icons map[string]image.Imagevar loadIconsOnce sync.Oncefunc loadIcons() { icons = map[string]image.Image{ "left": loadIcon("left.png"), "up": loadIcon("up.png"), "right": loadIcon("right.png"), "down": loadIcon("down.png"), }}// Icon 是并发安全的func Icon(name string) image.Image { loadIconsOnce.Do(loadIcons) return icons[name]}
==goroutine高并发下 *** 作map 要用 sync.Map 来 *** 作==
//sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等 *** 作方法var m = sync.Map{}func main() { wg := sync.WaitGroup{} for i := 0; i < 20; i++ { wg.Add(1) go func(n int) { key := strconv.Itoa(n) m.Store(key, n) value, _ := m.Load(key) fmt.Printf("k=:%v,v:=%v\n", key, value) wg.Done() }(i) } wg.Wait()}
==代码中的加锁 *** 作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子 *** 作来保证并发安全,因为原子 *** 作是Go语言提供的方法它在用户态就可以完成,因此性能比加锁 *** 作更好。Go语言中原子 *** 作由内置的标准库sync/atomic提供。==
// 原子 *** 作版加函数func atomicAdd() { atomic.AddInt64(&x, 1) wg.Done()}
make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身
变量之间使用引用地址直接可以改变
package mainfunc swap(a, b *int) { var temp int temp = *a *a = *b *b = temp}func main() { var a, b = 1, 2 swap(&a, &b) fmt.Println(a) fmt.Println(b)}//指针小案例var a intfmt.Println(&a)var p *intp = &a*p = 20fmt.Println(a)
在参数赋值时可以不用用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“…”即可
package mainimport ( "fmt")func test(s string, n ...int) string { var x int for _, i := range n { x += i } return fmt.Sprintf(s, x)}func main() { s := []int{1, 2, 3} res := test("sum: %d", s...) // slice... 展开slice println(res)}
"_"标识符,用来忽略函数的某个返回值
没有参数的 return 语句返回各个返回变量的当前值。这种用法被称作“裸”返回。
func add(a, b int) (c int) { c = a + b return}func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a + b) / 2 return}func main() { var a, b int = 1, 2 c := add(a, b) sum, avg := calc(a, b) fmt.Println(a, b, c, sum, avg)}
命名返回参数允许 defer 延迟调用通过闭包读取和修改。
defer 是先进后出
package mainfunc add(x, y int) (z int) { defer func() { z += 100 }() z = x + y return}func main() { println(add(1, 2)) }
定义一维数组
var a [5]int = [5]int{1,2,5,6,7}var a = [...]int{1,2,3,5,6} d := [...]struct { name string age uint8 }{ {"user1", 10}, // 可省略元素类型。 {"user2", 20}, // 别忘了最后一行的逗号。 }
定义二维数组 第 2 纬度不能用 "..."
var b [3][2]int = [3][2]int{{1,2},{3,4},{5,6}}var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
定义slice
全局:var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}var slice0 []int = arr[start:end] var slice1 []int = arr[:end] var slice2 []int = arr[start:] var slice3 []int = arr[:] var slice4 = arr[:len(arr)-1] //去掉切片的最后一个元素局部:arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}slice5 := arr[start:end]slice6 := arr[:end] slice7 := arr[start:] slice8 := arr[:] slice9 := arr[:len(arr)-1] //去掉切片的最后一个元素//通过make来创建切片var slice []type = make([]type, len)slice := make([]type, len)slice := make([]type, len, cap)
定义map
scoreMap := make(map[string]int) scoreMap["张三"] = 90 scoreMap["小明"] = 100 // 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值 v, ok := scoreMap["张三"] if ok { fmt.Println(v) } else { fmt.Println("查无此人") } //使用delete()函数删除键值对 delete(scoreMap, "小明")//将小明:100从map中删除
数组按照下标排序输出
tetcc := make(map[int]string,5) tetcc[1] = "smallsha" tetcc[5] = "smallsha1" tetcc[3] = "smallsha2" sli := []int{} for i := range tetcc { sli = append(sli,i) } sort.Ints(sli) for i := 0; i < len(tetcc); i++ { fmt.Println("内容",tetcc[sli[i]]) } fmt.Printf("%#v\n", sli) return
if判断
if test2 :=19; test2> 20 { fmt.Println("test11212121212") }else if test2 < 20 { fmt.Println("test1111") }
switch使用
test3 := 80 switch test3 { case 80: fmt.Println("1") fallthrough //可以使用fallthrough强制执行后面的case代码。 case 90: fmt.Println("2") case 100: fmt.Println("3") default: fmt.Println("default") }
多个参数调用
func test(s string, n ...int) string { var x int for _, i := range n { x += i } return fmt.Sprintf(s, x)} s := []int{1, 2, 3} res := test("sum: %d", s...) // slice... 展开slice println(res)
闭包使用
func a() func() int { i := 0 b := func() int{ i++ fmt.Println(i) return i } return b} ccccc := a() ccccc() ccccc() return
关键字 defer 用于注册延迟调用。
这些调用直到 return 前才被执。因此,可以用来做资源清理。
多个defer语句,按先进后出的方式执行
惯例是:导致关键流程出现不可修复性错误的使用 panic,其他使用 error。
func main() { test()}func test() { defer func() { if err := recover(); err != nil { println(err.(string)) // 将 interface{} 转型为具体类型。 } }() panic("panic error!")}
表达式
package mainimport "fmt"type User struct { ID int name string}func (self *User) test() { fmt.Printf("%p, %v\n", self, self)}func main() { u := User{1, "Tom"} u.test() mValue := u.Test mValue() // 隐式传递 receiver mExpression := (*User).Test mExpression(&u) // 显式传递 receiver}
定义error http://www.topgoer.com/%E6%96%B9%E6%B3%95/%E8%87%AA%E5%AE%9A%E4%B9%89error.html
//返回异常package mainimport ( "errors" "fmt")func getCircleArea(radius float32) (area float32, err error) { if radius < 0 { // 构建个异常对象 err = errors.New("半径不能为负") return } area = 3.14 * radius * radius return}func main() { area, err := getCircleArea(-5) if err != nil { fmt.Println(err) } else { fmt.Println(area) }}//系统抛异常package mainimport "fmt"func test01() { a := [5]int{0, 1, 2, 3, 4} a[1] = 123 fmt.Println(a) //a[10] = 11 index := 10 a[index] = 10 fmt.Println(a)}func getCircleArea(radius float32) (area float32) { if radius < 0 { // 自己抛 panic("半径不能为负") } return 3.14 * radius * radius}func test02() { getCircleArea(-5)}//func test03() { // 延时执行匿名函数 // 延时到何时?(1)程序正常结束 (2)发生异常时 defer func() { // recover() 复活 恢复 // 会返回程序为什么挂了 if err := recover(); err != nil { fmt.Println(err) } }() getCircleArea(-5) fmt.Println("这里有没有执行")}func test04() { test03() fmt.Println("test04")}func main() { test04()}//自定义errorpackage mainimport ( "fmt" "os" "time")type PathError struct { path string op string createTime string message string}func (p *PathError) Error() string { return fmt.Sprintf("path=%s \nop=%s \ncreateTime=%s \nmessage=%s", p.path, p.op, p.createTime, p.message)}func Open(filename string) error { file, err := os.Open(filename) if err != nil { return &PathError{ path: filename, op: "read", message: err.Error(), createTime: fmt.Sprintf("%v", time.Now()), } } defer file.Close() return nil}func main() { err := Open("/Users/5lmh/Desktop/go/src/test.txt") switch v := err.(type) { case *PathError: fmt.Println("get path error,", v) default: }}
interface 应用
// 空接口作为函数参数func show(a interface{}) { fmt.Printf("type:%T value:%v\n", a, a)}// 空接口作为map值 var studentInfo = make(map[string]interface{}) studentInfo["name"] = "李白" studentInfo["age"] = 18 studentInfo["marrIEd"] = false fmt.Println(studentInfo)
go调度 sync.WaitGroup
var wg sync.WaitGroupfunc hello(i int) { defer wg.Done() // goroutine结束就登记-1 fmt.Println("Hello Goroutine!", i)}func main() { for i := 0; i < 10; i++ { wg.Add(1) // 启动一个goroutine就登记+1 go hello(i) } wg.Wait() // 等待所有登记的goroutine都结束}
go runtime.Gosched()
//让出cpu时间片,重新等待安排任务(大概意思就是本来计划的好好的周末出去烧烤,但是你妈让你去相亲,两种情况第一就是你相亲速度非常快,见面就黄不耽误你继续烧烤,第二种情况就是你相亲速度特别慢,见面就是你侬我侬的,耽误了烧烤,但是还馋就是耽误了烧烤你还得去烧烤)package mainimport ( "fmt" "runtime")func main() { go func(s string) { for i := 0; i < 2; i++ { fmt.Println(s) } }("world") // 主协程 for i := 0; i < 2; i++ { // 切一下,再次分配任务 runtime.Gosched() fmt.Println("hello") }}
runtime.Goexit()
//退出当前协程(一边烧烤一边相亲,突然发现相亲对象太丑影响烧烤,果断让她滚蛋,然后也就没有然后了)package mainimport ( "fmt" "runtime")func main() { go func() { defer fmt.Println("A.defer") func() { defer fmt.Println("B.defer") // 结束协程 runtime.Goexit() defer fmt.Println("C.defer") fmt.Println("B") }() fmt.Println("A") }() for { }}
runtime.GOMAXPROCS
//Go1.5版本之后,默认使用全部的cpu逻辑核心数///两个任务只有一个逻辑核心,此时是做完一个任务再做另一个任务。 将逻辑核心数设为2,此时两个任务并行执行,代码如下。func a() { for i := 1; i < 10; i++ { fmt.Println("A:", i) }}func b() { for i := 1; i < 10; i++ { fmt.Println("B:", i) }}func main() { runtime.GOMAXPROCS(2) go a() go b() time.Sleep(time.Second)}
通道1.对一个关闭的通道再发送值就会导致panic。
2.对一个关闭的通道进行接收会一直获取值直到通道为空。
3.对一个关闭的并且没有值的通道执行接收 *** 作会得到对应类型的零值。
4.关闭一个已经关闭的通道会导致panic。
5.chan<- int是一个只能发送的通道,可以发送但是不能接收;
6 <-chan int是一个只能接收的通道,可以接收但是不能发送。
func counter(out chan<- int) { for i := 0; i < 100; i++ { out <- i } close(out)}func squarer(out chan<- int, in <-chan int) { for i := range in { out <- i * i } close(out)}func printer(in <-chan int) { for i := range in { fmt.Println(i) }}func main() { ch1 := make(chan int) ch2 := make(chan int) go counter(ch1) go squarer(ch2, ch1) printer(ch2)}
通道使用案例type Job struct { ID int RandNum int}type Result struct { job *Job sum int}func createPool(num int, jobChan chan *Job,resultChan chan *Result) { for i := 0; i < num; i++ { go func(jobChan chan *Job,resultChan chan *Result) { for i2 := range jobChan { r_num := i2.RandNum var sum int for r_num !=0 { tmp := r_num % 10 sum += tmp r_num /= 10 } r := &Result{ job: i2, sum: sum, } resultChan <- r } }(jobChan,resultChan) }}func main() { flag.Parse() jobChan := make(chan *Job, 128) resultChan := make(chan *Result, 128) createPool(64, jobChan, resultChan) // 4.开个打印的协程 go func(resultChan chan *Result) { // 遍历结果管道打印 for result := range resultChan { fmt.Printf("job ID:%v randnum:%v result:%d\n", result.job.ID, result.job.RandNum, result.sum) } }(resultChan) var ID int // 循环创建job,输入到管道 for { ID++ // 生成随机数 r_num := rand.Int() job := &Job{ ID: ID, RandNum: r_num, } jobChan <- job } return }
select 监听通道 select { case <-chan1: // 如果chan1成功读到数据,则进行该case处理语句 case chan2 <- 1: // 如果成功向chan2写入数据,则进行该case处理语句 default: // 如果上面都没有成功,则进入default处理流程 }
flag使用 和 os.args var name string var age int var marrIEd bool var delay time.Duration flag.StringVar(&name, "name", "张三", "姓名") flag.Intvar(&age, "age", 18, "年龄") flag.BoolVar(&marrIEd, "marrIEd", false, "婚否") flag.DurationVar(&delay, "d", 0, "延迟的时间间隔") 或者使用 name := flag.String("name", "张三", "姓名") age := flag.Int("age", 18, "年龄") marrIEd := flag.Bool("marrIEd", false, "婚否") delay := flag.Duration("d", 0, "时间间隔") //解析命令行参数 flag.Parse() fmt.Println(name, age, marrIEd, delay) //返回命令行参数后的其他参数 fmt.Println(flag.Args()) //返回命令行参数后的其他参数个数 fmt.Println(flag.NArg()) //返回使用的命令行参数个数 fmt.Println(flag.NFlag()) //os.args if len(os.Args) > 0 { for index, arg := range os.Args { fmt.Printf("args[%d]=%v\n", index, arg) } }
Log文件 logfile, err := os.Openfile("./smallsha.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Println("open log file Failed, err:", err) return } log.Setoutput(logfile) //设置日志文件写入 log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.SetPrefix("[smallsha]") log.Printf("%s","smallsha") log.Println("test") //log.Panic("test1") //log.Fatalln("test2") logger := log.New(os.Stdout, "<New>", log.Lshortfile|log.Ldate|log.Ltime) logger.Println("这是自定义的logger记录的日志。")
循环 *** 作arr := [5]int{1,2,4,5,6,8}for i,num :=range arr { fmt.Println(i,num)}//while for 循环配合通道 var ( ch11 = make(chan int) ch12 = make(chan int) ) go func() { for i := 0; i < 10; i++ { ch11 <- i } close(ch11) }() go func() { for { i, ok := <-ch11 if !ok { break } ch12 <- i * i } close(ch12) }() for i := range ch12 { fmt.Println(i) }
指针const MAX int =3func main(){ a :=[]int{1,3,5} var ptr [MAX]*int; for i = 0; i < MAX; i++ { ptr[i] = &a[i] /* 整数地址赋值给指针数组 */ } for i = 0; i < MAX; i++ { fmt.Printf("a[%d] = %d\n", i,*ptr[i] ) }}
strconv 使用 s3, _ := strconv.ParseBool("1") fmt.Printf("%# v\n", pretty.Formatter(s3)) return //int 转 string s2 := 100 i2 := strconv.Itoa(s2) fmt.Printf("%# v\n", pretty.Formatter(i2)) return //string 转 int s1 := "100" i1, err := strconv.Atoi(s1) if err != nil { fmt.Println(err) return } fmt.Printf("%# v\n", pretty.Formatter(i1)) return
template使用可以注册httppackage logicimport ( "fmt" "HTML/template" "net/http")func init() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println(err) return }}type UserInfo struct { name string Gender string Age int}func sayHello(w http.ResponseWriter,r *http.Request) { // 解析指定文件生成模板对象 tmpl, err := template.Parsefiles("./hello.HTML") if err != nil { fmt.Println("create template Failed, err:", err) return } // 利用给定数据渲染模板,并将结果写入w user := UserInfo{ name: "枯藤", Gender: "男", Age: 18, } // 利用给定数据渲染模板,并将结果写入w tmpl.Execute(w, user)}
定义结构体package mainimport "fmt"type Books struct { Title string author string subject string book_ID int}func main() { var Book1 Books /* 声明 Book1 为 Books 类型 */ var Book2 Books /* 声明 Book2 为 Books 类型 */ /* book 1 描述 */ Book1.Title = "Go 语言" Book1.author = "www.runoob.com" Book1.subject = "Go 语言教程" Book1.book_ID = 6495407 /* book 2 描述 */ Book2.Title = "Python 教程" Book2.author = "www.runoob.com" Book2.subject = "Python 语言教程" Book2.book_ID = 6495700 /* 打印 Book1 信息 */ printBook(&Book1) /* 打印 Book2 信息 */ printBook(&Book2)}func printBook( book *Books ) { fmt.Printf( "Book Title : %s\n", book.Title) fmt.Printf( "Book author : %s\n", book.author) fmt.Printf( "Book subject : %s\n", book.subject) fmt.Printf( "Book book_ID : %d\n", book.book_ID)}//结构体new 和赋值 type Person struct { Username string `Json:"username"` Password string `Json:"password"`}//声明构造方法func newPerson(username string, password string) *Person { return &Person{ Username: username, Password: password, }}//定义修改结构体的方法func (p *Person) setUsername(username string) { p.Username = username}
map *** 作package mainimport "fmt"func main() { var countryCAPItalMap map[string]string /*创建集合 */ countryCAPItalMap = make(map[string]string) /* map插入key - value对,各个国家对应的首都 */ countryCAPItalMap [ "France" ] = "巴黎" countryCAPItalMap [ "Italy" ] = "罗马" countryCAPItalMap [ "Japan" ] = "东京" countryCAPItalMap [ "India " ] = "新德里" /*使用键输出地图值 */ for country := range countryCAPItalMap { fmt.Println(country, "首都是", countryCAPItalMap [country]) } /*查看元素在集合中是否存在 */ cAPItal, ok := countryCAPItalMap [ "American" ] /*删除元素*/ delete(countryCAPItalMap, "France") /*如果确定是真实的,则存在,否则不存在 */ /*fmt.Println(cAPItal) */ /*fmt.Println(ok) */ if (ok) { fmt.Println("American 的首都是", cAPItal) } else { fmt.Println("American 的首都不存在") }}
声明变量 package main import "fmt" func main() { var a string = "Runoob" fmt.Println(a) var b, c int = 1, 2 fmt.Println(b, c) }声明方法 package main import "fmt" func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("Google", "Runoob") fmt.Println(a, b) }定义数组 var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} package main import "fmt" func main() { var n [10]int /* n 是一个长度为 10 的数组 */ var i,j int /* 为数组 n 初始化元素 */ for i = 0; i < 10; i++ { n[i] = i + 100 /* 设置元素为 i + 100 */ } /* 输出每个数组元素的值 */ for j = 0; j < 10; j++ { fmt.Printf("Element[%d] = %d\n", j, n[j] ) } }
Go 语言结构体package mainimport "fmt"type Books struct { Title string author string subject string book_ID int}func main() { var Book1 Books /* 声明 Book1 为 Books 类型 */ var Book2 Books /* 声明 Book2 为 Books 类型 */ /* book 1 描述 */ Book1.Title = "Go 语言" Book1.author = "www.runoob.com" Book1.subject = "Go 语言教程" Book1.book_ID = 6495407 /* book 2 描述 */ Book2.Title = "Python 教程" Book2.author = "www.runoob.com" Book2.subject = "Python 语言教程" Book2.book_ID = 6495700 /* 打印 Book1 信息 */ fmt.Printf( "Book 1 Title : %s\n", Book1.Title) fmt.Printf( "Book 1 author : %s\n", Book1.author) fmt.Printf( "Book 1 subject : %s\n", Book1.subject) fmt.Printf( "Book 1 book_ID : %d\n", Book1.book_ID) /* 打印 Book2 信息 */ fmt.Printf( "Book 2 Title : %s\n", Book2.Title) fmt.Printf( "Book 2 author : %s\n", Book2.author) fmt.Printf( "Book 2 subject : %s\n", Book2.subject) fmt.Printf( "Book 2 book_ID : %d\n", Book2.book_ID)}结构体作为函数参数 func printBook( book Books ) { fmt.Printf( "Book Title : %s\n", book.Title) fmt.Printf( "Book author : %s\n", book.author) fmt.Printf( "Book subject : %s\n", book.subject) fmt.Printf( "Book book_ID : %d\n", book.book_ID) }
声明函数和方法区别#函数func main() { sum := add(1, 2) fmt.Println(sum)}func add(a, b int) int { return a + b}#方法type person struct { name string}func (p person) String() string{ return "the person name is "+p.name}func main() { p:=person{name:"张三"} fmt.Println(p.String())}#可变参数func main() { print("1","2","3")}func print (a ...interface{}){ for _,v:=range a{ fmt.Print(v) } fmt.Println()}
修改字符串 需要先转换成 byte 或者 runefunc changeString() { s1 := "hello" // 强制类型转换 byteS1 := []byte(s1) byteS1[0] = 'H' fmt.Println(string(byteS1)) s2 := "博客" runes2 := []rune(s2) runes2[0] = '狗' fmt.Println(string(runes2))}
总结 以上是内存溢出为你收集整理的GO 语言快速学习 | PHP转GO笔记全部内容,希望文章能够帮你解决GO 语言快速学习 | PHP转GO笔记所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)