Go语言学习

摘自Go语言结构|菜鸟教程

Go 语言的基础组成有以下几个部分:

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释

其中安装的时候测试的代码:

package main

import "fmt"

func main() {
   /* 这是我的第一个简单的程序 */
   fmt.Println("Hello, World!")
}
  1. 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

  2. 下一行 import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。

  3. 下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。

  4. 下一行 /*...*/ 是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。

  5. 下一行 fmt.Println(...) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
    使用 fmt.Print("hello, world\n") 可以得到相同的结果。
    Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。

  6. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

————————————————————分割线————————————————————

以下按照个人习惯整理,主要参考:

Go语言教程|菜鸟教程

http://c.biancheng.net/golang/intro/

一、数据类型

Go语言的基本类型有:

  • bool
  • string
  • int、int8、int16、int32、int64
  • uint、uint8、uint16、uint32、uint64、uintptr
  • byte // uint8 的别名
  • rune // int32 的别名 代表一个 Unicode 码
  • float32、float64
  • complex64、complex128

声明变量:

var name type

举例:

package main

import "fmt"

func main() {
	var name string
	name = "Tom"
	fmt.Println(name)

	var age int
	age=20
	fmt.Println(age)
}

输出:

这样写也OK:

package main

import "fmt"

func main() {
	var name string = "Tom"
	fmt.Println(name)

	var age int = 20
	fmt.Println(age)
}

“当一个变量被声明之后,系统自动赋予它该类型的零值:int 为 0,float 为 0.0,bool 为 false,string 为空字符串,指针为 nil 等。所有的内存在 Go 中都是经过初始化的。”

举例(只初始化,不赋值):

package main

import "fmt"

func main() {
	var name string//字符串
	fmt.Println(name)

	var age int//整型
	fmt.Println(age)

	var flag bool//布尔型
	fmt.Println(flag)

	var inch float64//浮点型
	fmt.Println(inch)

	var point *int//指针
	fmt.Println(point)

	var score [10] int//数组
	fmt.Println(score)
}

输出:

另有懒人特供版:

package main

import "fmt"

func main() {

	var (
		name string//字符串
		age int//整型
		flag bool//布尔型
		inch float64//浮点型
		point *int//指针
		score [10] int//数组
	)
	fmt.Println(name)
	fmt.Println(age)
	fmt.Println(flag)
	fmt.Println(inch)
	fmt.Println(point)
	fmt.Println(score)
}

像这样同时定义多个变量也是work的:

package main

import "fmt"

func main() {
	var age1, age2, age3 int = 20, 21, 22
	fmt.Println(age1)
	fmt.Println(age2)
	fmt.Println(age3)
	fmt.Printf("%v %v %v\n", age1, age2, age3)
}

输出:

 

同时,即使不定义数据类型,Go也会自己判断(一个成熟的语言×):

package main

import (
	"fmt"
	"reflect"
)

func main() {

	var (
		name = "Tom"//字符串
		age = 20//整型
	)
	fmt.Println(name)
	fmt.Println(age)
	fmt.Println("type:", reflect.TypeOf(name))
	fmt.Println("type:", reflect.TypeOf(age))
}

输出:

其他声明变量的方式:

:=

package main

import "fmt"

func main() {
	age := 20
	fmt.Println(age)
}

输出:

注意:由于使用了:=,而不是赋值的=,因此推导声明写法的左值变量必须是没有定义过的变量。若定义过,将会发生编译错误。

如果 hp 已经被声明过,但依然使用:=时编译器会报错,代码如下:

package main

import "fmt"

func main() {
	var age int
	age := 20
	fmt.Println(age)
}

报错信息如下:

GOROOT=null #gosetup
GOPATH=null #gosetup
go.exe build -i -o D:\SOFTware\GoLand\GOcode\go_build_awesomeProject_.exe . #gosetup
go build: -i flag is deprecated
# _/D_/SOFTware/GoLand/awesomeProject
.\hello.go:7:6: no new variables on left side of :=

Compilation finished with exit code 2

字符串操作:http://c.biancheng.net/view/17.html

 

二、运算符

注意:优先级值越大,表示优先级越高。

有关逻辑运算符:

下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False。

运算符描述实例
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。(A && B) 为 False
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。(A || B) 为 True
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。!(A && B) 为 True

其他:https://www.runoob.com/go/go-operators.html

 

三、数组

数组的声明语法如下:

var 数组变量名 [元素数量]Type

(可参见上文有关变量声明部分的举例)

var score [10] int

数组初始化

1.确定数组大小的:

package main

import "fmt"

func main() {
	var age = [10] int {20, 21, 22, 23, 20, 21, 22, 23, 20, 21}
	fmt.Println(age)
	fmt.Println(age[0])
	fmt.Println(age[9])
}

输出:

不过要注意,Go这里不具备和Python一样玩的条件,至少要保证索引值的正确。
比如,如果把age[0]和age[9]改成age[-1]和age[10]:

package main

import "fmt"

func main() {
	var age = [10] int {20, 21, 22, 23, 20, 21, 22, 23, 20, 21}
	fmt.Println(age)
	fmt.Println(age[-1])
	fmt.Println(age[10])
}

并不能输出倒数第一个,报错如下:

GOROOT=null #gosetup
GOPATH=null #gosetup
go.exe build -i -o D:\SOFTware\GoLand\GOcode\go_build_awesomeProject_.exe . #gosetup
go build: -i flag is deprecated
# _/D_/SOFTware/GoLand/awesomeProject
.\hello.go:8:17: invalid array index -1 (index must be non-negative)
.\hello.go:9:17: invalid array index 10 (out of bounds for 10-element array)

Compilation finished with exit code 2

2.不确定数组长度

可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

package main

import "fmt"

func main() {
	var age = [...] int {20, 21, 22, 23, 20, 21, 22, 23, 20, 21}
	fmt.Println(age)
	fmt.Println(age[0])
	fmt.Println(age[9])
}

输出:

要注意,此处虽然未确定数组长度,但是还是会因为索引值的问题报错的(仍以-1和10实验,报错如下)

go build: -i flag is deprecated
# _/D_/SOFTware/GoLand/awesomeProject
.\hello.go:8:17: invalid array index -1 (index must be non-negative)
.\hello.go:9:17: invalid array index 10 (out of bounds for 10-element array)

Compilation finished with exit code 2

修改数组中元素

直接改就可以了:

package main

import "fmt"

func main() {
	var age = [...] int {20, 21, 22, 23, 20, 21, 22, 23, 20, 21}
	age[1] = 30
	fmt.Println(age)
	fmt.Println(age[0])
	fmt.Println(age[9])
}

输出:

多维数组

package main

import "fmt"

func main() {
	var age = [3][4] int {
		{0, 9, 8, 7},
		{1, 2, 3, 4},
		{5, 6, 7, 8},
	}

	fmt.Println(age)
	fmt.Println(age[0])
	fmt.Println(age[1])
	fmt.Println(age[2])
}

输出:

 

其余部分见循环语句部分


 

四、条件语句

if

语法
if condition {
// do something
}

if condition {
// do something
} else {
// do something
}

if condition1 {
// do something
} else if condition2 {
// do something else
}else {
// catch-all or default
}

举例(参考https://blog.csdn.net/study_in/article/details/102919019生成伪随机数):

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().Unix())
	var flag int
	flag = rand.Intn(40)
	fmt.Println(flag)
	if flag < 20 {
			fmt.Println("小于20")
	} else if flag == 20{
			fmt.Println("等于20")
	} else {
			fmt.Println("大于20")
	}

}

输出:

switch

Go 编程语言中 switch 语句的语法如下:

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

举例:

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().Unix())
	var flag int
	flag = rand.Intn(40)
	fmt.Println(flag)

	switch{
	case flag < 20:
		fmt.Println("小于20")
	case flag == 20:
		fmt.Println("等于20")
	default:
		fmt.Println("大于20")
	}

}

输出:

select

Go 编程语言中 select 语句的语法如下:

select {
    case communication clause  :
       statement(s);      
    case communication clause  :
       statement(s);
    /* 你可以定义任意数量的 case */
    default : /* 可选 */
       statement(s);
}

https://www.runoob.com/go/go-select-statement.html

这个例子没看懂

select语句类似于switch语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

      select可以监听channel的数据流动,用于处理异步IO操作,它最大的限制就是每个case语句里必须是一个IO操作(channel操作)

      select是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。一个默认的子句应该总是可运行的。
————————————————
版权声明:本文为CSDN博主「Aaron_1997」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Aaron_1997/article/details/110196040

package main

import "fmt"

func main() {
	var i, j int
	var col1, col2 chan int

	select{
	case i = <- col1:
		fmt.Println("received", i, "from col1")
	case col2 <- j:
		fmt.Println("sent", j, "to col2")
	default:
		fmt.Println("no communication")
	}

}

输出:

 

五、循环语句

语法
与多数语言不同的是,Go语言中的循环语句只支持 for 关键字,而不支持 while 和 do-while 结构,关键字 for 的基本使用方法与C语言和 C++ 中非常接近:
sum := 0
for i := 0; i < 10; i++ {
    sum += i
}
可以看到比较大的一个不同在于 for 后面的条件表达式不需要用圆括号()括起来,Go语言还进一步考虑到无限循环的场景,让开发者不用写无聊的 for(;;){}和do{} while(1);,而直接简化为如下的写法:
sum := 0
for {
    sum++
    if sum > 100 {
        break
    }
}

举例:

package main

import "fmt"

func main() {
	var cnt[10] int
	for i := 0; i < 10;i++ {
		cnt[i] = i
	}
	fmt.Println(cnt)
}

输出:

嵌套:

package main

import "fmt"

func main() {
	var cnt[10] int
	var sum int
	for i := 0; i < 10;i++ {
		cnt[i] = i
		for j :=10; j < 11; j++ {
			sum = i+j
			fmt.Println(sum)
		}
	}
	fmt.Println(cnt)
}

输出:

另:

package main

import "fmt"

func main() {
	var sum[10] int
	for i := 0; i < 10;i++ {
		for j :=10; j < 11; j++ {
			sum[i] = i+j
			fmt.Println(sum)
		}
	}
}

输出:

题外话:我感觉这样一点一点填进去好治愈

 

六、函数

Go 语言函数定义格式如下:

func function_name( [parameter list] ) [return_types] {
   函数体
}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,函数名和参数列表一起构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

举例:

package main

import "fmt"

func main() {
	var (
		string1 = "hello "
		string2 = "world!"
	)
	hello_world(string1, string2)
}

func hello_world(str1, str2 string) (string, string){
	fmt.Print(str1)
	fmt.Print(str2)
	return str1, str2
}

输出:

 

————————————————————分割线————————————————————

用之前注册白嫖的搜狗语音合成做个测试

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {

	url := "https://api.zhiyin.sogou.com/apis/tts/v1/synthesize"
	appid := "创建任务时得到的appid"
	token := "鉴权得到的token"

	payload := strings.NewReader(`{
		"input": {
			"text": "语音合成测试"
		},
		"config": {
			"audio_config": {
				"audio_encoding": "MP3",
				"pitch": 1,
				"volume": 1,
				"speaking_rate": 1
			},
			"voice_config": {
				"language_code": "zh-cmn-Hans-CN",
				"speaker": "male"
			}
		}
	}`)

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Appid", appid)
	req.Header.Add("Authorization", "Bearer "+token)

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	if res.StatusCode == http.StatusOK {
		ioutil.WriteFile("audio.mp3", body, 0644)
		fmt.Printf("save finish")
	} else {
		fmt.Println("err :", res.StatusCode)
	}

}

输出得到的mp3文件属性:

鉴权代码:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

func CreateToken(appid, appkey string, exp time.Duration) (string, error) {

	reqbody, err := json.Marshal(map[string]string{
		"appid":  appid,
		"appkey": appkey,
		"exp":    fmt.Sprintf("%ds", int(exp.Seconds())),
	})

	resp, err := http.Post(
		"https://api.zhiyin.sogou.com/apis/auth/v1/create_token",
		"application/json",
		bytes.NewBuffer(reqbody))

	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("http status: %s", resp.Status)
	}

	respbody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var js struct {Token string}
	err = json.Unmarshal(respbody, &js)
	return js.Token, nil
}

func main() {
	fmt.Println(CreateToken("appid,创建应用时获得", "appkey,创建应用时获得", time.Hour))
}

输出结果:

 

 

PS,搜狗给的demo就很坑,真的,开头就是

package sogouspeech

还没有调用,下面给的调用部分也莫名其妙(我删了uuid,所以少一个参数)

sogouspeech.CreateToken("your_app_id", "your_app_key", time.Hour, "can_be_empty")

会疯狂报错

GOROOT=null #gosetup
GOPATH=null #gosetup
go.exe build -i -o D:\SOFTware\GoLand\GOcode\go_build_awesomeProject_.exe -gcflags "-N -l" . #gosetup
go build: -i flag is deprecated
# _/D_/SOFTware/GoLand/awesomeProject
.\hello.go:46:14: undefined: sogouspeech

Compilation finished with exit code 2

 

——————————再次更新——————————

分开获得token和合成语音太过麻烦了,百度的demo都是写在一起的,所以为了能弄明白怎么把百度的demo迁移到go上,把搜狗的demo合在一起了。

如下:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

func CreateToken(appid, appkey string, exp time.Duration) (string, error) {
	/*json.Marshal:将某种数据结构生成为json字符串
	    Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key
	  	来快速检索数据,key 类似于索引,指向数据的值。
	    Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,
	  	我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
	*/
	reqbody, err := json.Marshal(map[string]string{
		"appid":  appid,
		"appkey": appkey,
		"exp":    fmt.Sprintf("%ds", int(exp.Seconds())),
	})
	/*
	   map定义
	   声明变量,默认map是nil
	   var map_variable map[kay_data_type]value_data_type

	      fmt.Sprintf 格式化输出

	   请求体
	   {
	   	"appid": string,
	   	"appkey": string,
	   	"exp": string,
	   	"uuid": string
	   }

	   exp:访问令牌失效时间,有效范围0-10小时。如一小时为“3600s”,1分钟为“60s”
	      注:本字符串格式是 google.protobuf.Duration 类型的 JSON 序列化,
	   根据相关标准,时间应格式化为类似 "123s",即数字 + 后缀s,表示多少秒。

	*/
	resp, err := http.Post(
		"https://api.zhiyin.sogou.com/apis/auth/v1/create_token",
		"application/json",
		bytes.NewBuffer(reqbody))
	/*
	   如果在使用bytes.NewBuffer的时候参数是[]byte的slice的话
	   缓冲器里就是这个slice的内容,如果参数是nil的话,意思是New一个空的缓冲器里
	*/
	if err != nil {
		return "", err
	}
	/*
	      if err != nil {
	          // do something....
	      }
	   	当出现不等于nil的时候,说明出现某些错误了,需要我们对这个错误进行一些处理,
	   而如果等于nil说明运行正常。

	   注:
	   每种类型对应的零值:
	   bool--> false
	   numbers--> 0
	   string--> ""
	   pointers-->nil
	   slices-->nil
	   map-->nil
	   channels-->nil
	   functions-->nil
	   interfaces-->nil
	*/
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("http status: %s", resp.Status)
	}

	respbody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var js struct {Token string}
	err = json.Unmarshal(respbody, &js)
	return js.Token, nil
}

func main() {
	//var token_str string
	token, err_str := CreateToken("获得的appid", "获得的appkey", time.Hour)
	fmt.Println(token)
	fmt.Println(err_str)


	url := "https://api.zhiyin.sogou.com/apis/tts/v1/synthesize"
	appid := "获得的appid"


	payload := strings.NewReader(`{
		"input": {
			"text": "搜狗语音合成测试文本"
		},
		"config": {
			"audio_config": {
				"audio_encoding": "MP3",
				"pitch": 1,
				"volume": 1,
				"speaking_rate": 1
			},
			"voice_config": {
				"language_code": "zh-cmn-Hans-CN",
				"speaker": "male"
			}
		}
	}`)

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Appid", appid)
	req.Header.Add("Authorization", "Bearer "+token)

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	if res.StatusCode == http.StatusOK {
		ioutil.WriteFile("audio.mp3", body, 0644)
		fmt.Printf("save finish")
	} else {
		fmt.Println("err :", res.StatusCode)
	}


}

输出:

输出音频在代码所在的文件夹

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值