• [交流吐槽] 老板能不能上个JBL GO2 音乐金砖,家里迫切需要一个。
    老板,能不能上个JBL GO2 音乐金砖,家里迫切需要一个。谢谢了。
  • [问题求助] 【openGauss】编译openGauss-prometheus-exporter 有要求go必须是多少版本以上的吗?
    编译openGauss-prometheus-exporter 有要求go必须是多少版本以上的吗?
  • [技术干货] goland安装教程[转载]
    go语言有很多的插件来编译程序  其中最为好的就是goland 转载一篇关于安装goland的文章希望大家喜欢原文链接:https://blog.csdn.net/weixin_42809940/article/details/82423171go语言环境安装下载地址:https://golang.google.cn/dl/goland软件安装下载地址:http://www.jetbrains.com/go/download/#section=windowsgoland许可证认证码可以到网站http://idea.lanyus.com/查询认证码。github 上clone项目配置系统的环境变量GOPATH为任意一个目录,用于存放src下的package目录再然后把项目放入GOPTH目录下的src目录下使用go get 安装各种包golang.org/x/net 安装方法为了使包的导入方式不变,我们需要在src目录下面构造目录结构$mkdir -p  $GOPATH/src/golang.org/x/$cd $GOPATH/src/golang.org/x/$git clone https://github.com/golang/net.git net$go install net执行go install之后没有提示,就说明安装好了。windows安装go-sqlite3失败,提示找不到gccwindows安装go-sqlite3失败,提示找不到gcc go get github.com/mattn/go-sqlite3时失败,提示exec: “gcc”: executable file not found in %PATH%,是因为没有安装gcc。 去http://tdm-gcc.tdragon.net/download下载一个,32位windows下载 tdm-gcc-4.8.1-3.exe,64位下载 tdm64-gcc-4.8.1-3.exe注:为保证能够成功编译,建议安装所有的包。安装完成以后,配置环境变量path中添加gcc安装目录,C:\TDM-GCC-64\bin运行go get 指令 提示unrecognized import path运行指令如下:go get google.golang.org/grpc错误提示:package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc" (https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 74.125.28.14:443: i/o timeout)解决方法:1、建立相关文件夹mkdir -p $GOPATH/src/google.golang.org/2、命令行打开文件夹cd $GOPATH/src/google.golang.org3、从Github上克隆其他的仓库 git clone https://github.com/Agzs/grpc grpc4、 安装仓库cd $GOPATH/src/go install google.golang.org/grpc5、 结束最后运行成功。
  • [技术干货] Golang极简入门教程(三):并发支持
    这篇文章主要介绍了Golang极简入门教程(三):并发支持,本文讲解了goroutine线程、channel 操作符等内容,需要的朋友可以参考下Golang 运行时(runtime)管理了一种轻量级线程,被叫做 goroutine。创建数十万级的 goroutine 是没有问题的。范例:复制代码代码如下:package main import (    "fmt"    "time") func say(s string) {    for i := 0; i < 5; i++ {        time.Sleep(100 * time.Millisecond)        fmt.Println(s)    }} func main() {    // 开启一个 goroutine 执行 say 函数    go say("world")    say("hello")}我们使用 channel 和 goroutine 通讯。channel 中是一种带有类型的通道,被用于接收和发送特定类型的值。操作符 <- 被叫做 channel 操作符(这个操作符中箭头表明了值的流向):复制代码代码如下:// 发送 v 到 channel chch <- v// 接收 channel ch 中的值并赋值给 vv := <-ch使用 channel 和 goroutine 通讯能够避免显式使用锁机制,通过 channel 发送和接收值时默认是阻塞的。通过 make 函数创建 channel:复制代码代码如下:// int 指定 channel 收发值的类型为 intch := make(chan int)一个完整的例子:复制代码代码如下:package main import "fmt" // 计算数组 a 中所有元素值之和func sum(a []int, c chan int) {    sum := 0    for _, v := range a {        sum += v    }    // 计算结果发送到 channel c    c <- sum} func main() {    a := []int{7, 2, 8, -9, 4, 0}     // 创建 channel c    c := make(chan int)     go sum(a[:len(a)/2], c)    go sum(a[len(a)/2:], c)     // 接收两个 goroutine 发送的计算结果    x, y := <-c, <-c     fmt.Println(x, y, x+y)}package main import "fmt" // 计算数组 a 中所有元素值之和func sum(a []int, c chan int) {    sum := 0    for _, v := range a {        sum += v    }    // 计算结果发送到 channel c    c <- sum} func main() {    a := []int{7, 2, 8, -9, 4, 0}     // 创建 channel c    c := make(chan int)     go sum(a[:len(a)/2], c)    go sum(a[len(a)/2:], c)     // 接收两个 goroutine 发送的计算结果    x, y := <-c, <-c     fmt.Println(x, y, x+y)}channel 可以带有一个缓冲区(buffer)来缓存被传递的值,向 channel 中发送时只有缓冲区满的情况下会阻塞,接收 channel 中的值时只有在缓冲区空的情况下阻塞:复制代码代码如下:package main import "fmt" func main() {    // 创建 channel,缓冲区长度为 2    c := make(chan int, 2)    // 由于 channel 的缓冲区长度为 2    // 因此发送不会阻塞    c <- 1    c <- 2    fmt.Println(<-c)    fmt.Println(<-c)}发送者可以调用 close 来关闭 channel,接收者可以检测到 channel 是否被关闭:复制代码代码如下:// 这里的 ok 为 false 表示已经没有值可以接收了,并且 channel 被关闭了v, ok := <-ch不要向已经关闭的 channel 发送值了(will cause a panic)。我们可以使用 for range 来接收 channel 中的值:复制代码代码如下:package main import "fmt" func fibonacci(n int, c chan int) {    x, y := 0, 1    for i := 0; i < n; i++ {        c <- x        x, y = y, x+y    }    // 必须要关闭 c    close(c)} func main() {    c := make(chan int, 10)    go fibonacci(cap(c), c)    // 这里 for 和 range 组合使用    // 不断的接收 c 中的值一直到它被关闭    for i := range c {        fmt.Println(i)    }}通常来说,我们不需要主动的关闭 channel。但有时候接收者必须被告知已经没有值可以接收了,这时候主动关闭是必要的,例如终止 for range 循环。使用 select 语句可以让一个 goroutine 等待多个通讯操作。select 会阻塞直到某个 case 能够运行,如果同时存在多个可执行的,那么将随机选择一个:复制代码代码如下:package main import "fmt" func fibonacci(c, quit chan int) {    x, y := 0, 1    for {        select {        case c <- x:            x, y = y, x+y        // 控制此线程退出        case <-quit:            fmt.Println("quit")            return        }    }} func main() {    c := make(chan int)    quit := make(chan int)    go func() {        for i := 0; i < 10; i++ {            fmt.Println(<-c)        }        quit <- 0    }()    fibonacci(c, quit)}select 中的 default 会在没有任何 case 可执行时执行(类似于 switch):复制代码代码如下:package main import (    "fmt"    "time") func main() {    // 创建一个 tick channel    // 在 100 毫秒后会向 tick channel 中发送当前时间    tick := time.Tick(100 * time.Millisecond)    // 创建一个 boom channel    // 在 500 毫秒后会向 boom channel 中发送当前时间    boom := time.After(500 * time.Millisecond)    for {        select {        case <-tick:            fmt.Println("tick.")        case <-boom:            fmt.Println("BOOM!")            return        default:            fmt.Println("    .")            time.Sleep(50 * time.Millisecond)        }    }}
  • [技术干货] Golang极简入门教程(二):方法和接口
    这篇文章主要介绍了Golang极简入门教程(二):方法和接口,本文同时讲解了错误、匿名域等内容,需要的朋友可以参考下方法在 Golang 中没有类,不过我们可以为结构体定义方法。我们看一个例子:复制代码代码如下:package main import (    "fmt"    "math") type Vertex struct {    X, Y float64} // 结构体 Vertex 的方法// 这里的方法接收者(method receiver)v 的类型为 *Vertexfunc (v *Vertex) Abs() float64 {    return math.Sqrt(v.X*v.X + v.Y*v.Y)} func main() {    v := &Vertex{3, 4}    fmt.Println(v.Abs())}在这里方法的接收者使用指针类型而非值类型主要出于以下几点考虑(类似 C/C++ 等语言):1.避免方法每次调用时,对接收者的不必要的拷贝2.在方法内可以修改接收者的值我们可以为任意类型定义方法,但以下情况除外:1.如果类型定义在其他包中,不能为其定义方法2.如果类型是基础类型,不能为其定义方法复制代码代码如下:package main import (    "fmt"    "math") // 定义一个类型 MyFloattype MyFloat float64 // 注意此方法关联的类型是 MyFloat 而不是 *MyFloatfunc (f MyFloat) Abs() float64 {    if f < 0 {        return float64(-f)    }    return float64(f)} func main() {    f := MyFloat(-math.Sqrt2)    fmt.Println(f.Abs())}接口(interface)接口也是一种类型(就像结构体一样)。一个接口类型包含了一组方法,一个接口类型能够持有那些实现了这些方法的值。范例:复制代码代码如下:// 定义接口 Absertype Abser interface {    Abs() float64} // 定义结构体 Vertextype Vertex struct {    X, Y float64} // 实现方法 Absfunc (v *Vertex) Abs() float64 {    return math.Sqrt(v.X*v.X + v.Y*v.Y)} func main() {    v := Vertex{3, 4}    // 成功,能够持有 *Vertex 类型的值    var a Abser = &v    // 出错,不能持有 Vertex 类型的值    // 因为在 *Vertex 上定义了方法 Abs,而未在 Vertex 上定义    var b Abser = v}错误Golang 提供了一个 error 接口:复制代码代码如下:type error interface {    Error() string}我们通过 os.Open 函数来了解一下 error 的用法:复制代码代码如下:// 此函数用于打开一个文件// 返回的第二个值为 error 类型func Open(name string) (file *File, err error)简单的例子:复制代码代码如下:package main import (    "fmt"    "os") func main() {    _, err := os.Open("test.txt")    // 如果 err 不为 nil 表示存在错误    if err != nil {        fmt.Println(err)    }}创建一个 error 值的最简单方式是使用 errors.New 函数:复制代码代码如下:func Sqrt(f float64) (float64, error) {    if f < 0 {        // 出错时返回一个错误        return 0, errors.New("math: square root of negative number")    }    // ...}我们也可以定义一个新的 error 的实现(也就是实现接口 error):复制代码代码如下:type NegativeSqrtError float64 func (f NegativeSqrtError) Error() string {    return fmt.Sprintf("math: square root of negative number %g", float64(f))}匿名域结构体中可以存在只有类型而没有名字的域,它们被叫做匿名域。例如:复制代码代码如下:struct {    T1    *T2}一个结构体的匿名域中的域或者方法可以被此结构体实例直接访问:复制代码代码如下:package main import "fmt" type Car struct {    wheelCount int} func (car *Car) numberOfWheels() int {    return car.wheelCount} type Ferrari struct {    Car} func main() {    f := Ferrari{Car{4}}    fmt.Println("A Ferrari has this many wheels: ", f.numberOfWheels())}
  • [互动交流] AOS服务有提供go语言的SDK吗?
    项目准备使用AOS服务,请教下有没有go语言的SDK可以用?感谢
  • [技术干货] go 并发
    Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。goroutine 语法格式:go 函数名( 参数列表 )例如:go f(x, y, z)开启一个新的 goroutine:f(x, y, z)Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。实例package mainimport (        "fmt"        "time")func say(s string) {        for i := 0; i < 5; i++ {                time.Sleep(100 * time.Millisecond)                fmt.Println(s)        }}func main() {        go say("world")        say("hello")}执行以上代码,你会看到输出的 hello 和 world 是没有固定先后顺序。因为它们是两个 goroutine 在执行:worldhellohelloworldworldhellohelloworldworldhello通道(channel)通道(channel)是用来传递数据的一个数据结构。通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。ch <- v    // 把 v 发送到通道 chv := <-ch  // 从 ch 接收数据           // 并把值赋给 v声明一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:ch := make(chan int)注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。以下实例通过两个 goroutine 来计算数字之和,在 goroutine 完成计算后,它会计算两个结果的和:实例package mainimport "fmt"func sum(s []int, c chan int) {        sum := 0        for _, v := range s {                sum += v        }        c <- sum // 把 sum 发送到通道 c}func main() {        s := []int{7, 2, 8, -9, 4, 0}        c := make(chan int)        go sum(s[:len(s)/2], c)        go sum(s[len(s)/2:], c)        x, y := <-c, <-c // 从通道 c 中接收        fmt.Println(x, y, x+y)}输出结果为:-5 17 12通道缓冲区通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:ch := make(chan int, 100)带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。注意:如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。实例package mainimport "fmt"func main() {    // 这里我们定义了一个可以存储整数类型的带缓冲通道        // 缓冲区大小为2        ch := make(chan int, 2)        // 因为 ch 是带缓冲的通道,我们可以同时发送两个数据        // 而不用立刻需要去同步读取数据        ch <- 1        ch <- 2        // 获取这两个数据        fmt.Println(<-ch)        fmt.Println(<-ch)}执行输出结果为:Go 遍历通道与关闭通道Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片。格式如下:v, ok := <-ch如果通道接收不到数据后 ok 就为 false,这时通道就可以使用 close() 函数来关闭。实例package mainimport (        "fmt")func fibonacci(n int, c chan int) {        x, y := 0, 1        for i := 0; i < n; i++ {                c <- x                x, y = y, x+y        }        close(c)}func main() {        c := make(chan int, 10)        go fibonacci(cap(c), c)        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据        // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不        // 会结束,从而在接收第 11 个数据的时候就阻塞了。        for i := range c {                fmt.Println(i)        }}执行输出结果为:0112358132134
  • [技术干货] go错误处理
    Go 错误处理Go 语言通过内置的错误接口提供了非常简单的错误处理机制。error类型是一个接口类型,这是它的定义:type error interface {    Error() string}我们可以在编码中通过实现 error 接口类型来生成错误信息。函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:func Sqrt(f float64) (float64, error) {    if f < 0 {        return 0, errors.New("math: square root of negative number")    }    // 实现}在下面的例子中,我们在调用Sqrt的时候传递的一个负数,然后就得到了non-nil的error对象,将此对象与nil比较,结果为true,所以fmt.Println(fmt包在处理error时会调用Error方法)被调用,以输出错误,请看下面调用的示例代码:result, err:= Sqrt(-1)if err != nil {   fmt.Println(err)}实例实例package mainimport (    "fmt")// 定义一个 DivideError 结构type DivideError struct {    dividee int    divider int}// 实现 `error` 接口func (de *DivideError) Error() string {    strFormat := `    Cannot proceed, the divider is zero.    dividee: %d    divider: 0`    return fmt.Sprintf(strFormat, de.dividee)}// 定义 `int` 类型除法运算的函数func Divide(varDividee int, varDivider int) (result int, errorMsg string) {    if varDivider == 0 {            dData := DivideError{                    dividee: varDividee,                    divider: varDivider,            }            errorMsg = dData.Error()            return    } else {            return varDividee / varDivider, ""    }}func main() {    // 正常情况    if result, errorMsg := Divide(100, 10); errorMsg == "" {            fmt.Println("100/10 = ", result)    }    // 当除数为零的时候会返回错误信息    if _, errorMsg := Divide(100, 0); errorMsg != "" {            fmt.Println("errorMsg is: ", errorMsg)    }}执行以上程序,输出结果为:100/10 =  10errorMsg is:      Cannot proceed, the divider is zero.    dividee: 100    divider: 0
  • [技术干货] go语言接口
    Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。实例实例/* 定义接口 */type interface_name interface {   method_name1 [return_type]   method_name2 [return_type]   method_name3 [return_type]   ...   method_namen [return_type]}/* 定义结构体 */type struct_name struct {   /* variables */}/* 实现接口方法 */func (struct_name_variable struct_name) method_name1() [return_type] {   /* 方法实现 */}...func (struct_name_variable struct_name) method_namen() [return_type] {   /* 方法实现*/}实例实例package mainimport (    "fmt")type Phone interface {    call()}type NokiaPhone struct {}func (nokiaPhone NokiaPhone) call() {    fmt.Println("I am Nokia, I can call you!")}type IPhone struct {}func (iPhone IPhone) call() {    fmt.Println("I am iPhone, I can call you!")}func main() {    var phone Phone    phone = new(NokiaPhone)    phone.call()    phone = new(IPhone)    phone.call()}在上面的例子中,我们定义了一个接口Phone,接口里面有一个方法call()。然后我们在main函数里面定义了一个Phone类型变量,并分别为之赋值为NokiaPhone和IPhone。然后调用call()方法,输出结果如下:I am Nokia, I can call you!I am iPhone, I can call you!
  • [技术干货] go语言递归函数
    递归,就是在运行的过程中调用自己。语法格式如下:func recursion() {   recursion() /* 函数调用自身 */}func main() {   recursion()}Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。递归函数对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等。阶乘以下实例通过 Go 语言的递归函数实例阶乘:实例package mainimport "fmt"func Factorial(n uint64)(result uint64) {    if (n > 0) {        result = n * Factorial(n-1)        return result    }    return 1}func main() {      var i int = 15    fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))}以上实例执行输出结果为:15 的阶乘是 1307674368000斐波那契数列以下实例通过 Go 语言的递归函数实现斐波那契数列:实例package mainimport "fmt"func fibonacci(n int) int {  if n < 2 {   return n  }  return fibonacci(n-2) + fibonacci(n-1)}func main() {    var i int    for i = 0; i < 10; i++ {       fmt.Printf("%d\t", fibonacci(i))    }}以上实例执行输出结果为:0    1    1    2    3    5    8    13    21    34
  • [技术干货] go map元集合
    Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。定义 Map可以使用内建函数 make 也可以使用 map 关键字来定义 Map:/* 声明变量,默认 map 是 nil */var map_variable map[key_data_type]value_data_type/* 使用 make 函数 */map_variable := make(map[key_data_type]value_data_type)如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对实例下面实例演示了创建和使用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" ] /*如果确定是真实的,则存在,否则不存在 */    /*fmt.Println(capital) */    /*fmt.Println(ok) */    if (ok) {        fmt.Println("American 的首都是", capital)    } else {        fmt.Println("American 的首都不存在")    }}以上实例运行结果为:France 首都是 巴黎Italy 首都是 罗马Japan 首都是 东京India  首都是 新德里American 的首都不存在delete() 函数delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key。实例如下:实例package mainimport "fmt"func main() {        /* 创建map */        countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}        fmt.Println("原始地图")        /* 打印地图 */        for country := range countryCapitalMap {                fmt.Println(country, "首都是", countryCapitalMap [ country ])        }        /*删除元素*/ delete(countryCapitalMap, "France")        fmt.Println("法国条目被删除")        fmt.Println("删除元素后地图")        /*打印地图*/        for country := range countryCapitalMap {                fmt.Println(country, "首都是", countryCapitalMap [ country ])        }}以上实例运行结果为:原始地图India 首都是 New delhiFrance 首都是 ParisItaly 首都是 RomeJapan 首都是 Tokyo法国条目被删除删除元素后地图Italy 首都是 RomeJapan 首都是 TokyoIndia 首都是 New delhi
  • [技术干货] go语言范围
    Go 语言范围(Range)Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。实例实例package mainimport "fmt"func main() {    //这是我们使用range去求一个slice的和。使用数组跟这个很类似    nums := []int{2, 3, 4}    sum := 0    for _, num := range nums {        sum += num    }    fmt.Println("sum:", sum)    //在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。    for i, num := range nums {        if num == 3 {            fmt.Println("index:", i)        }    }    //range也可以用在map的键值对上。    kvs := map[string]string{"a": "apple", "b": "banana"}    for k, v := range kvs {        fmt.Printf("%s -> %s\n", k, v)    }    //range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。    for i, c := range "go" {        fmt.Println(i, c)    }}以上实例运行输出结果为:sum: 9index: 1a -> appleb -> banana0 1031 111
  • [技术干货] Go 语言切片(Slice)
    Go 语言切片是对数组的抽象。Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。定义切片你可以声明一个未指定大小的数组来定义切片:var identifier []type切片不需要说明长度。或使用 make() 函数来创建切片:var slice1 []type = make([]type, len)也可以简写为slice1 := make([]type, len)也可以指定容量,其中 capacity 为可选参数。make([]T, length, capacity)这里 len 是数组的长度并且也是切片的初始长度。切片初始化s :=[] int {1,2,3 } 直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。s := arr[:] 初始化切片 s,是数组 arr 的引用。s := arr[startIndex:endIndex] 将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。s := arr[startIndex:] 默认 endIndex 时将表示一直到arr的最后一个元素。s := arr[:endIndex] 默认 startIndex 时将表示从 arr 的第一个元素开始。s1 := s[startIndex:endIndex] 通过切片 s 初始化切片 s1。s :=make([]int,len,cap) 通过内置函数 make() 初始化切片s,[]int 标识为其元素类型为 int 的切片。len() 和 cap() 函数切片是可索引的,并且可以由 len() 方法获取长度。切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。以下为具体实例:实例package mainimport "fmt"func main() {   var numbers = make([]int,3,5)   printSlice(numbers)}func printSlice(x []int){   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)}以上实例运行输出结果为:len=3 cap=5 slice=[0 0 0]空(nil)切片一个切片在未初始化之前默认为 nil,长度为 0,实例如下:实例package mainimport "fmt"func main() {   var numbers []int   printSlice(numbers)   if(numbers == nil){      fmt.Printf("切片是空的")   }}func printSlice(x []int){   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)}以上实例运行输出结果为:len=0 cap=0 slice=[]切片是空的切片截取可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound],实例如下:实例package mainimport "fmt"func main() {   /* 创建切片 */   numbers := []int{0,1,2,3,4,5,6,7,8}      printSlice(numbers)   /* 打印原始切片 */   fmt.Println("numbers ==", numbers)   /* 打印子切片从索引1(包含) 到索引4(不包含)*/   fmt.Println("numbers[1:4] ==", numbers[1:4])   /* 默认下限为 0*/   fmt.Println("numbers[:3] ==", numbers[:3])   /* 默认上限为 len(s)*/   fmt.Println("numbers[4:] ==", numbers[4:])   numbers1 := make([]int,0,5)   printSlice(numbers1)   /* 打印子切片从索引  0(包含) 到索引 2(不包含) */   number2 := numbers[:2]   printSlice(number2)   /* 打印子切片从索引 2(包含) 到索引 5(不包含) */   number3 := numbers[2:5]   printSlice(number3)}func printSlice(x []int){   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)}执行以上代码输出结果为:len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]numbers == [0 1 2 3 4 5 6 7 8]numbers[1:4] == [1 2 3]numbers[:3] == [0 1 2]numbers[4:] == [4 5 6 7 8]len=0 cap=5 slice=[]len=2 cap=9 slice=[0 1]len=3 cap=7 slice=[2 3 4]append() 和 copy() 函数如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。实例package mainimport "fmt"func main() {   var numbers []int   printSlice(numbers)   /* 允许追加空切片 */   numbers = append(numbers, 0)   printSlice(numbers)   /* 向切片添加一个元素 */   numbers = append(numbers, 1)   printSlice(numbers)   /* 同时添加多个元素 */   numbers = append(numbers, 2,3,4)   printSlice(numbers)   /* 创建切片 numbers1 是之前切片的两倍容量*/   numbers1 := make([]int, len(numbers), (cap(numbers))*2)   /* 拷贝 numbers 的内容到 numbers1 */   copy(numbers1,numbers)   printSlice(numbers1)   }func printSlice(x []int){   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)}以上代码执行输出结果为:len=0 cap=0 slice=[]len=1 cap=1 slice=[0]len=2 cap=2 slice=[0 1]len=5 cap=6 slice=[0 1 2 3 4]len=5 cap=12 slice=[0 1 2 3 4]
  • [技术干货] Go 语言结构体
    Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。结构体表示一项记录,比如保存图书馆的书籍记录,每本书有以下属性:Title :标题Author : 作者Subject:学科ID:书籍ID定义结构体结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:type struct_variable_type struct {   member definition   member definition   ...   member definition}一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:variable_name := structure_variable_type {value1, value2...valuen}或variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}实例如下:实例package mainimport "fmt"type Books struct {   title string   author string   subject string   book_id int}func main() {    // 创建一个新的结构体    fmt.Println(Books{"Go 语言", "www.run.com", "Go 语言教程", 6495407})    // 也可以使用 key => value 格式    fmt.Println(Books{title: "Go 语言", author: "www.run.com", subject: "Go 语言教程", book_id: 6495407})    // 忽略的字段为 0 或 空   fmt.Println(Books{title: "Go 语言", author: "www.run.com"})}输出结果为:{Go 语言 www.run.com Go 语言教程 6495407}{Go 语言 www.run.com Go 语言教程 6495407}{Go 语言 www.run.com  0}访问结构体成员如果要访问结构体成员,需要使用点号 . 操作符,格式为:结构体.成员名"结构体类型变量使用 struct 关键字定义,实例如下:实例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.run.com"   Book2.subject = "Python 语言教程"   Book2.book_id = 649570   /* 打印 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)}以上实例执行运行结果为:Book 1 title : Go 语言Book 1 author : www.run.comBook 1 subject : Go 语言教程Book 1 book_id : 6495407Book 2 title : Python 教程Book 2 author : www.runcomBook 2 subject : Python 语言教程Book 2 book_id : 6495700结构体作为函数参数你可以像其他数据类型一样将结构体类型作为参数传递给函数。并以以上实例的方式访问结构体变量:实例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.run.com"   Book1.subject = "Go 语言教程"   Book1.book_id = 6495407   /* book 2 描述 */   Book2.title = "Python 教程"   Book2.author = "www.run.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)}以上实例执行运行结果为:Book title : Go 语言Book author : www.run.comBook subject : Go 语言教程Book book_id : 6495407Book title : Python 教程Book author : www.run.comBook subject : Python 语言教程Book book_id : 6495700结构体指针你可以定义指向结构体的指针类似于其他指针变量,格式如下:var struct_pointer *Books以上定义的指针变量可以存储结构体变量的地址。查看结构体变量地址,可以将 & 符号放置于结构体变量前:struct_pointer = &Book1使用结构体指针访问结构体成员,使用 "." 操作符:struct_pointer.title接下来让我们使用结构体指针重写以上实例,代码如下:实例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.run.com"   Book1.subject = "Go 语言教程"   Book1.book_id = 6495407   /* book 2 描述 */   Book2.title = "Python 教程"   Book2.author = "www.run.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)}以上实例执行运行结果为:Book title : Go 语言Book author : www.runoob.comBook subject : Go 语言教程Book book_id : 6495407Book title : Python 教程Book author : www.runoob.comBook subject : Python 语言教程Book book_id : 6495700
  • [技术干货] go语言指针
    Go 语言指针Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。接下来让我们来一步步学习 Go 语言指针。我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。以下实例演示了变量在内存中地址:实例package mainimport "fmt"func main() {   var a int = 10      fmt.Printf("变量的地址: %x\n", &a  )}执行以上代码输出结果为:变量的地址: 20818a220现在我们已经了解了什么是内存地址和如何去访问它。接下来我们将具体介绍指针。什么是指针一个指针变量指向了一个值的内存地址。类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:var var_name *var-typevar-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:var ip *int        /* 指向整型*/var fp *float32    /* 指向浮点型 */本例中这是一个指向 int 和 float32 的指针。如何使用指针指针使用流程:定义指针变量。为指针变量赋值。访问指针变量中指向地址的值。在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。实例package mainimport "fmt"func main() {   var a int= 20   /* 声明实际变量 */   var ip *int        /* 声明指针变量 */   ip = &a  /* 指针变量的存储地址 */   fmt.Printf("a 变量的地址是: %x\n", &a  )   /* 指针变量的存储地址 */   fmt.Printf("ip 变量储存的指针地址: %x\n", ip )   /* 使用指针访问值 */   fmt.Printf("*ip 变量的值: %d\n", *ip )}以上实例执行输出结果为:a 变量的地址是: 20818a220ip 变量储存的指针地址: 20818a220*ip 变量的值: 20Go 空指针当一个指针被定义后没有分配到任何变量时,它的值为 nil。nil 指针也称为空指针。nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。一个指针变量通常缩写为 ptr。查看以下实例:实例package mainimport "fmt"func main() {   var  ptr *int   fmt.Printf("ptr 的值为 : %x\n", ptr  )}以上实例输出结果为:ptr 的值为 : 0空指针判断:if(ptr != nil)     /* ptr 不是空指针 */if(ptr == nil)    /* ptr 是空指针 */
总条数:152 到第
上滑加载中