go未入门学习记录
开发环境配置go1.12.17+goland
参考链接macos配置go语言以及goland开发环境
语法学习记录
package main
//kaiyu.liu@shopee.com golang学习笔记
//参考资料 https://www.kancloud.cn/itfanr/go-quick-learn/81636
//参考视频 https://www.bilibili.com/video/BV1eK4y1b7fj?p=14
import (
"bufio"
"fmt"
"math"
"os"
"strings"
)
//go中函数构造语法 func关键字 + 函数名 + 参数列表 + 返回值列表,返回值只有一个类型时括号可以省略
func foo()(string,int){
return "1234",900
}
//预先设置返回值的名字,可以直接return,支持多返回值
func slice_sum(arr []int) (sum int) {
sum = 0
for _, elem := range arr {
sum += elem
}
return
}
//go函数支持可变长参数,要求:可变长参数列表里数据类型相同以及可变长参数只能是函数的最后一个参数
func sum(base int, arr ...int) int {
sum := base
for _, val := range arr {
sum += val
}
return sum
}
//闭包函数,类似于函数指针,将函数封装成一个变量,特性在于闭包函数对其外层的函数参数具有修改能力
func example() int{
var arr1 = []int{1, 2, 3, 4, 5}
var sum = func(arr ...int) int {
total_sum := 0
for _, val := range arr {
total_sum += val
}
return total_sum
}
fmt.Println(sum(arr1...))
return 0
}
//递归函数 就那样没啥区别
//go语言中的异常处理
//defer,在函数运行结束的时候再运行语句
func testDefer() {
fname := "D:\\Temp\\test.txt"
f, err := os.Open(fname)
defer f.Close()
if err != nil {
os.Exit(1)
}
bReader := bufio.NewReader(f)
for {
line, ok := bReader.ReadString('\n')
if ok != nil {
break
}
fmt.Println(strings.Trim(line, "\r\n"))
}
}
//panic&recover异常关键字,panic触发异常,cecover终止一场并返回传递给panic的值,配合defer一定会运行
func test_panic() {
defer func() {
msg := recover()
fmt.Println(msg)
}()
fmt.Println("I am walking and singing...")
panic("It starts to rain cats and dogs")
}
func main(){
fmt.Println("Hello World!")
var name string //go变量声明 var 名字 类型
var(
a string = "111"
b int = 111
c bool = false
)
fmt.Println(a,b,c,name)
fmt.Printf("%s1234%d\n",a,b)
//变量类型推倒 类似auto
var y = 200
fmt.Println(y)
//短变量声明,只能在函数内部
aaa:=123
fmt.Println(aaa)
//匿名变量
aaaa,_:=foo()
fmt.Println(aaaa)
//常量声明
const pi float32 = 3.1415
const(
aaaaaa = 1000
bbbbb
ccccc
//默认与aaaaa一样
)
//枚举 遇到const初始化为0,const中每增加一行都会使我们iota加一,
const(
a_ = iota //0
_ = iota //1
c_ = 1000
d_ = iota //3
)
const(
_ = iota
kb = 1<<(10*iota)
mb = 1<<(10*iota)
)
const(
a__,b__ = iota+1,iota+2 //1,2
c__,d__ = iota+1,iota+2 //2,3
)
//数据类型整型 浮点型 布尔型 字符串 数组 切片 结构体 函数 map 通道
//int8 int16 int32 int64 uint8-16-32-64 uint8=byte int16 = short int64 = long
//int 与 uint取决于操作系统为int32或int64
//内置函数len()
var a1 int = 10
fmt.Printf("%d \n",a1)
var a2 int = 077 //8进制 0开头
fmt.Printf("%o \n",a2)
var a3 int = 0xff //16进制 0x开头
fmt.Printf("%x \n",a3)
//var a4 int = 0b11 //2进制 0b开头
//fmt.Printf("%x \n",a4) 1.13开始支持2进制
fmt.Printf("%p \n",&a1) //%p表示16进制内存地址
//float32 float64两个常量 math.MaxFloat32 math.MaxFloat64 %f打印
fmt.Printf("%f \n",math.MaxFloat32)
//go中无法将布尔值与其他类型转换
//字符串utf-8编码
// \n换行 \r回车 \t制表 \'单引号 \"双引号 \反斜杠
fmt.Println("\"c:\\go\"")
var s = `多行
文本
不用转义
`
fmt.Println(s)
//字符串操作
// 求长度len(s)
//拼接字符串 a+b
ss := fmt.Sprintf("%s%s",s,s)
fmt.Println(ss)
//分割
ret := strings.Split(ss,"行")
fmt.Println(ret)
//判断包含 返回布尔
retBool := strings.Contains(ss,"行")
fmt.Println(retBool)
//前缀与后缀
ret3 := strings.HasPrefix(ss,"多")
ret4 := strings.HasSuffix(ss,"义")
fmt.Println(ret3,ret4)
//求子串的位置
fmt.Println(strings.Index(ss,"行"))
fmt.Println(strings.LastIndex(ss,"行"))
//join
sss := []string{"11","22","33"}
fmt.Println(strings.Join(sss,"-"))
//byte与rune类型 分别表示单个的英文与中文,类似于char
a_rune := '中'
fmt.Println(a_rune)//输出编码
b_rune := "as中"
fmt.Println(len(b_rune)) //输出5 utf-8下一个中文占3字节
for i:=0;i<len(b_rune);i++{
fmt.Printf("%c\n",b_rune[i]) //中文会乱码
}
//for range循环 按照rune
for _,v:=range b_rune{
fmt.Sprintf("%c\n",v) //range循环返回两个,是索引+值
}
//字符串不能直接改变,转换为byte/rune在转换
s1 := "big"
s2 := []byte(s1)
s2[0] = 'p'
fmt.Println(string(s2))
//流程控制 if else for switch goto 没有while循环
if 3>2{
fmt.Println("123")
}else {
fmt.Println("sas")
}
if age2:=100;age2>90 { //age2作用域仅在for循环内部
fmt.Println("21")
}
age := 19
for age>10{ //类似于while循环
age--
}
for{
//死循环
if age>0 {
break
}
}
switch age{//只能写一个default
case 1 :
fmt.Println("11")
case 2 :
fmt.Println("123")
default:
fmt.Println("asdas")
}
switch n:=7; n {
case 1,3,5,7,9:
fmt.Println("jishu")
fallthrough //下穿,无条件地执行下一条case,
case 2,4,6,8:
fmt.Println("oushu")
}
//goto 跳出整个循环
for i:=1;i<3;i++{
for j:=1;j<3;j++ {
if (i == 2 && j == 2) {
goto label
}
}
}
label:
//运算符 +-*/ %求余 ++ 自增--自减
//数组
var xarray = [5]int{}
var xarray1 = [5]int{1,2,3,4,5}
var xarray2 = [5]int{}
var xarray3 = [...]string{
"11","22","33",
}
//多维数组 不赋值默认初始化为0
var xyarray = [3][2]int{
[2]int{1,2},
[2]int{3,4},
[2]int{5,6},
}
fmt.Println(xarray,xarray1,xarray2,xarray3,xyarray)
//切片,切片长度可变,包括长度len()与容量cap()两个属性。一种声明+make,取数组切片
var xsharp = make([]int,5) //cap5 len5
var xsharp1 = make([]int,5,10) //cap10 len5
fmt.Println(cap(xsharp),cap(xsharp1))
//数组切片赋值
var s_1 = xarray1[:3] //类似于py 包含下界不含上界
fmt.Println(s_1)
//append 函数可以将切片与某些元素组合,当数量超过容量,cap会变为2倍
slice1 := []int{1,2,3,4,5,6}
slice2 := make([]int,5,10)
copy(slice2,slice1) //将slice1赋值给slice2,但由于slice2长度为5,所以结果为【1,2,3,4,5】
//字典
var x_map = map[string]string{
"a":"apple",
"b":"banana",
"o":"orange",
}
//另一种定义以及初始化方式
var x_map2 map[string]string
x_map2 = make(map[string]string)
x_map2["a"] = "apple"
x_map2["b"] = "banana"
//x_map3 := make(map[string]string)
for key,val := range x_map{
fmt.Println(key,val)
}
fmt.Println(x_map["p"]) //会返回0,不存在的key值
//判断map中是否存在某个值,返回val为键值,ok为key值是否存在的布尔值变量
if val,ok := x_map["a"];ok{
fmt.Println(val)
}
//map中删除元素 delete 删除不存在的key值时不会报错
delete(x_map,"a")
//指针,通过传指针改变主函数中的参数值
var x_ptr *int
x_val := 10
x_ptr = &x_val
fmt.Println(x_val)
fmt.Println(x_ptr)
fmt.Println(*x_ptr)
//go中的new函数
x_ptr_new := new(int) //申请了一个存储整形变量的内存,并将此地址赋值给了x_ptr_new
*x_ptr_new = 10
}
//定义一个结构体
type Rect struct {
width float64
length float64
//width, length float64
}
//结构体的方法不需要定义在结构体内部,通过fun后标识所属结构体
func (rect Rect) area() float64 {
return rect.width * rect.length
}
//调用 rect.area()
/*使用方法
var rect Rect
rect.width = 100
rect.length = 200
//或者按照定于顺序赋值var rect = Rect{100, 200}
*/
//结构体类型指针
func structptr() {
var rect = new(Rect)
rect.width = 100
rect.length = 200
fmt.Println("Width:", rect.width, "Length:", rect.length,
"Area:", rect.area())
}
func (rect *Rect) double_area() float64 {
rect.width *= 2
rect.length *= 2
return rect.width * rect.length
}
//使用指针改变结构体的值。此处不改变值加不加*都可,不太严格。。
func ptrana() {
var rect = new(Rect)
rect.width = 100
rect.length = 200
fmt.Println(*rect)
fmt.Println("Double Width:", rect.width, "Double Length:", rect.length,
"Double Area:", rect.double_area())
fmt.Println(*rect)
}
//结构体内嵌直接调用,类似于继承
type Phone struct {
price int
color string
}
func (phone Phone) ringing() {
fmt.Println("ringing")
}
type IPhone struct {
Phone
model string
}
func inner() {
var p IPhone
p.price = 5000
p.color = "Black"
p.model = "iPhone 5"
p.ringing() //方法的继承与调用
fmt.Println("I have a iPhone:")
fmt.Println("Price:", p.price)
fmt.Println("Color:", p.color)
fmt.Println("Model:", p.model)
}
//结构体内嵌间接调用,这种类似于把结构体的一个对象当作成员
type Phonep struct{
price int
color string
}
type Myphone struct{
phone Phonep
model string
}
func inner2() {
var p Myphone
p.phone.price = 5000
p.phone.color = "Black"
p.model = "iPhone 5"
fmt.Println("I have a iPhone:")
fmt.Println("Price:", p.phone.price)
fmt.Println("Color:", p.phone.color)
fmt.Println("Model:", p.model)
}
//关键字interface 提供接口功能,其他类型只要实现这个方法就是实现了这个接口,不一定非要显式地声明。
//这难道是面向切面编程?跟java有点相似
type ppPhone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type iiIPhone struct {
}
func (iPhone iiIPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}
func testInterface() {
var phone ppPhone
phone = new(NokiaPhone)
phone.call()
phone = new(iiIPhone)
phone.call()
}