go语言常用

按位清零
看第二个操作数:
• 1: 清零
• 0: 保留

1 &^ 0 -> 1
1 &^ 1 -> 0
0 &^ 1 -> 0
0 &^ 0 -> 0
	//类型别名的定义 = ,类型定义没有=
	type MyInt2 = int
	var i1 MyInt2 = 1
	fmt.Printf("%T",i1)

0. 深入理解Go的slice及其扩容规则

    ints := []int{1, 2} 			// 扩容前 oldCap = 2
	fmt.Println(len(ints),cap(ints)) //2 2
	ints = append(ints, 3,4,5,6,7) // 
	fmt.Println(len(ints),cap(ints)) //7 8
	strs := []string{"a", "b"}
	fmt.Println(len(strs), cap(strs)) //2 2
	strs = append(strs, "c", "d", "e", "1", "2")
	fmt.Println(len(strs), cap(strs)) //7 7
  1. 预估扩容后容量
  2. 匹配到合适的内存规格
    所需内存 = 预估容量 * 元素类型大小
span等级   元素大小   span大小  对象个数
  1          8        8192     1024       
  2         16        8192      512        
  3         32        8192      256          
  4         48        8192      170       
  5         64        8192      128  
...
  65      28672       57344      2   
  66      32768       32768      1

申请内存时,内存管理模块会帮我们选足够大且最接近的内存规格,所以上面3个int类型需要24个字节的内存,那么实际分配的是第3个span等级,32个字节大小的内存span。

32个字节的内存span 能存储 大小为8个字节的int类型 共四个。所以真实的扩容容量为 4 而不是预估容量3。

一、Go语言中的数据类型转换

在go语言中,不同类型的变量之间赋值需要显示转换。

语法:T t=T(e)

    var i int=1
    //将i转换为float类型
    var j float32=float32(i)

基本数据类型转string

方法1:fmt.Sprintf(“%参数”,表达式)

func Sprintf(forat string,a …interface{}) string

Sprintf根据format参数生成格式化的字符串并返回该字符串

   var num int =1
    var str string="ok"
    //int类型转string
    str=fmt.Sprintf("%d",num)
    fmt.Printf("n=%v,v=%v",num,str)
    
    var e byte='a'
    var str string=""
    //byte类型转string 
    //%c 相应Unicode码点所表示的字符  
    str=fmt.Sprintf("%c",e)
    fmt.Printf("n=%v,v=%v",e,str)
    var b bool=true
    var str string=""
    
    //bool类型转string
    //%t true 或 false。
    //%q 双引号围绕的字符串,由Go语法安全地转义
    str=fmt.Sprintf("%t",b)
    fmt.Printf("n=%v,v=%q",b,str)

    var f float32=20.39
    var str string=""
    //float类型转string
    //%t 有小数而无指数
    //%q 双引号围绕的字符串,由Go语法安全地转义
    str=fmt.Sprintf("%f",f)
    fmt.Printf("n=%v,v=%q",f,str)

### 方法2:使用strconv包的函数
    var num int64=20
    var str string=""
    //int类型转string
    //base后面跟进制
    str=strconv.FormatInt(num,10)
    fmt.Printf("n=%v,v=%q",num,str)

    var num float64=20.55
    var str string=""
    //float类型转string
    //'f'是格式 10表示小数保留十位 64表示这个小数是float64
    str=strconv.FormatFloat(num,'f',10,64)
    fmt.Printf("n=%v,v=%q",num,str)

    var bl bool=true
    var str string=""
    //bool类型转string
    str=strconv.FormatBool(bl)
    fmt.Printf("n=%v,v=%q",bl,str)
 string类型转基本数据类型

    var num int=1
    var str string=""
    //string类型转int
    str=strconv.Itoa(num)
    fmt.Printf("n=%v,s=%q",num,str)
    
    var bl bool
    var str string="true"
    //string类型转bool
    //strconv.ParseBool会返回两个值
    bl,_=strconv.ParseBool(str)
    fmt.Printf("n=%v,s=%q",bl,str)
 
//string到int 
int,err:=strconv.Atoi(string) 
//string到int64 
int64, err := strconv.ParseInt(string, 10, 64) 
//int到string 
string:=strconv.Itoa(int) 
//int64到string 
string:=strconv.FormatInt(int64,10)
//string到float32(float64)
float,err := strconv.ParseFloat(string,32/64)
//float到string
string := strconv.FormatFloat(float32, 'E', -1, 32)
string := strconv.FormatFloat(float64, 'E', -1, 64)
// 'b' (-ddddp±ddd,二进制指数)
// 'e' (-d.dddde±dd,十进制指数)
// 'E' (-d.ddddE±dd,十进制指数)
// 'f' (-ddd.dddd,没有指数)
// 'g' ('e':大指数,'f':其它情况)
// 'G' ('E':大指数,'f':其它情况)

二、go语言的排序、结构体排序

golang中sort包用法
sort包中实现了3种基本的排序算法:插入排序.快排和堆排序

1. 基本类型 int 、 float64 和 string 的排序

对于 int 、 float64 和 string 数组或是分片的排序, go 分别提供了 sort.Ints() 、 sort.Float64s() 和 sort.Strings() 函数, 默认都是从小到大排序

    降序排序 
    sort.Sort(sort.Reverse(sort.IntSlice(intList)))
    sort.Sort(sort.Reverse(sort.Float64Slice(float8List)))
    sort.Sort(sort.Reverse(sort.StringSlice(stringList)))
    
args := "安倍12 Monday Tuesday Friday Sunday Wednesday Wednesday"
	split := strings.Split(args, " ")
	fmt.Println("前:",split)
	//go 1.8 新增排序. 支持其它类型
	sort.Slice(split, func(i, j int) bool { return len(split[i]) > len(split[j]) })
	fmt.Println("后:",split)
	//相同值保持原来顺序
	sort.SliceStable(split, func(i, j int) bool { return len(split[i]) > len(split[j]) })

三、go 发送http请求

Go语言开发发送Get和Post请求
Go 语言中要请求网页时,使用net/http包实现。
一般情况下有以下几种方法可以请求网页:
Get, Head, Post, 和 PostForm 发起 HTTP (或 HTTPS) 请求:

1.普通的get请求

package main

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

func main() {
    res,_ :=http.Get("https://www.baidu.com/")
    defer res.Body.Close()
    body,_ := ioutil.ReadAll(res.Body)
    fmt.Print(body)
}

2.带参数的get请求(参数不放在url里)

package main

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

func main(){
    params := url.Values{}
    Url, _:= url.Parse("https://www.baidu.com/")
    params.Set("name","zhaofan")
    params.Set("age","23")
    //如果参数中有中文参数,这个方法会进行URLEncode
    Url.RawQuery = params.Encode()
    urlPath := Url.String()
    fmt.Println(urlPath) //等同于https://www.xxx.com?age=23&name=zhaofan
    resp,_ := http.Get(urlPath)
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

3.get请求添加请求头

package main

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

func main() {
    client := &http.Client{}
    req,_ := http.NewRequest("GET","http://www.xxx.com",nil)
    req.Header.Add("name","zhaofan")
    req.Header.Add("age","3")
    resp,_ := client.Do(req)
   defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Printf(string(body))
}

4.post请求

package main

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

func main() {
    urlValues := url.Values{}
    urlValues.Add("name","zhaofan")
    urlValues.Add("age","22")
    resp, _ := http.PostForm("http://www.xxx.com",urlValues)
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

5.post请求的另一种方式`

package main

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

func main() {
    urlValues := url.Values{
        "name":{"zhaofan"},
        "age":{"23"},
    }
    reqBody:= urlValues.Encode()
    resp, _ := http.Post("http://www.xxx.com/post", "text/html",strings.NewReader(reqBody))
    defer resp.Body.Close()
    body,_:= ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

6.post请求发送json数据

package main

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

func main() {
    client := &http.Client{}
    data := make(map[string]interface{})
    data["name"] = "zhaofan"
    data["age"] = "23"
    bytesData, _ := json.Marshal(data)
    req, _ := http.NewRequest("POST","http://www.xxx.com",bytes.NewReader(bytesData))
    resp, _ := client.Do(req)
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))

}

7.post请求发送json数据,不用client

package main

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

func main() {
    data := make(map[string]interface{})
    data["name"] = "zhaofan"
    data["age"] = "23"
    bytesData, _ := json.Marshal(data)
    resp, _ := http.Post("http://www.xxx.com","application/json", bytes.NewReader(bytesData))
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

1. GET请求:

GET请求直接将参数拼接在URL里面,如同下面的示例:

func GetData() {
    client := &http.Client{}
    resp, err := client.Get("http://api.map.baidu.com/place/v2/suggestion?query=广州市天河区正佳广场&region=广州&city_limit=true&output=json&ak=yX8nC9Qzpckek7lY9gGWmlD4TFcA2tzYx3")
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(body))
}

2. POST请求

Post相关的请求有三种,分别是:http.post、http.postForm、http.Do请求。

http.post请求:

func httpPost() {
    resp, err := http.Post("http://www.01happy.com/demo/accept.php",
        "application/x-www-form-urlencoded",
        strings.NewReader("name=cjb"))
    if err != nil {
        fmt.Println(err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
    }
 
    fmt.Println(string(body))
}

注意:请求里面的第二个参数必须带,否则会报错的。

http.postForm:

func PostData() {
    //client := &http.Client{}
    resp, err := http.PostForm("https://www.pgyer.com/apiv2/app/view", url.Values{"appKey": {"62c99290f0cb2c567cb153c1fba75d867e"},
        "_api_key": {"584f29517115df2034348b0c06b3dc57"}, "buildKey": {"22d4944d06354c8dcfb16c4285d04e41"}})
 defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(body))

}

对于比较复杂的http请求,我们可以用到http.do的方式进行请求

    func httpDo() {
    client := &http.Client{}
 
    req, err := http.NewRequest("POST", "http://www.01happy.com/demo/accept.php", strings.NewReader("name=cjb"))
    if err != nil {
        // handle error
    }
 
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    req.Header.Set("Cookie", "name=anny")
 
    resp, err := client.Do(req)
 
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
    }
 
    fmt.Println(string(body))
    }

四、Go语言之时间戳和时间格式如何相互转换?

package main

import(
    "fmt"
    "time"
)

func main() {
    time.Now().Format("2006-01-02 15:04:05") //获取当前时间
    datetime := "2019-03-11 21:07:00"  		//待转化为时间戳的字符串

    //日期转化为时间戳
    timeLayout := "2006-01-02 15:04:05"  	//转化所需模板  
    loc, _ := time.LoadLocation("Local")    //获取时区  

	//调用转化方法,传入上面准备好的的三个参数
    tmp, _ := time.ParseInLocation(timeLayout, datetime, loc) 
    timestamp := tmp.Unix()    				//转化为时间戳(秒级) 类型是int64
    //timestamp = timestamp * 1000    		//转化为毫秒级
    log.Println(timestamp) 

    //时间戳转化为日期  
    datetime = time.Unix(timestamp, 0).Format(timeLayout)
    fmt.Println(datetime)    
}

五、for…range

在 range 迭代中,得到的值其实是元素的一份值拷贝,更新拷贝并不会更改原来的元素,即是拷贝的地址并不是原有元素的地址:

	func main() {
    data := []int{1, 2, 3}
    for _, v := range data {
        v *= 10        // data 中原有元素是不会被修改的
    }
    fmt.Println("data: ", data)    // data:  [1 2 3]
	}
如果要修改原有元素的值,应该使用索引直接访问:

	func main() {
    data := []int{1, 2, 3}
    for i, v := range data {
        data[i] = v * 10    
    }
    fmt.Println("data: ", data)    // data:  [10 20 30]
	}
如果你的集合保存的是指向值的指针,需稍作修改。依旧需要使用索引访问元素,不过可以使用 range 出来的元素直接更新原有值:

	func main() {
    data := []*struct{ num int }{{1}, {2}, {3},}
    for _, v := range data {
        v.num *= 10    // 直接使用指针更新
    }
    fmt.Println(data[0], data[1], data[2])    // &{10} &{20} &{30}
	}

for…range用于channel时,自动阻塞。无需再用写channel阻塞

六、defer

1.defer 函数的参数值

对 defer 延迟执行的函数,它的参数会在声明时候就会求出具体值,而不是在执行时才求值:

	// 在 defer 函数中参数会提前求值
	func main() {
    var i = 1
    defer fmt.Println("result: ", func() int { return i * 2 }())    //2
    i++
	}

七、go run/ go build

go build -gcflags -m main.go 或go run -gcflags -m main.go 能准确分析程序的变量分配位置
go run -race 启用数据竞争检测
go help build 查看go build 参数

八、死锁

主协程阻塞会导致死锁,子go程不会

九、四舍五入

Golang四舍五入保留两位小数

   func round(x float64){
   return int(math.Floor(x + 0/5))
   或
   	n10 := math.Pow10(2) // 保留2位小数。去掉末尾0
   fmt.Println(math.Trunc((9.815+0.5/n10)*n10) / n10) //9.82
   fmt.Println(math.Trunc((9.825+0.5/n10)*n10) / n10) //9.83
   fmt.Println(math.Trunc((9.835+0.5/n10)*n10) / n10) //9.84
   fmt.Println(math.Trunc((9.845+0.5/n10)*n10) / n10) //9.85
   fmt.Println(math.Trunc((3.3+0.5/n10)*n10) / n10) //3.3
   fmt.Println(math.Trunc((3.3000000000000003+0.5/n10)*n10) / n10) //3.3//保留n位小数
   func Trunc(str string, decimal int) string {
   num, _ := strconv.ParseFloat(str, 10)
   d := math.Pow10(decimal)
   return strconv.FormatFloat(math.Trunc((num+0.5/d)*d)/d, 'f', -1, 64)
   	}

十、json解析

Go实战–golang中使用号称全世界最快的JSON解析器json-iterator(json-iterator/go)
Go语言解析Json(使用jsonparser)

解析对象
body:=[]byte()
str:=gjson.GetBytes(body, “content”).String()
str := jsoniter.Get(body, “content”).ToString() // json-iterator
getString, err:= jsonparser.GetString(body, “content”) //jsonparser

11. 切片

函数中切片追加(添加新元素), 不影响原切片
修改原切片,使用切片指针

	slice:=[]int{1,2,3}
	var pslice *[]int
	pslice=&slice  //切片的指针变量(二级指针变量)
	(*pslice)[0]=10
	fmt.Println(slice)  //[10 2 3]


	slice:=[]int{1,2,3}	
     trans(&slice)
	fmt.Println(slice)   //[1 2 3 10]
	func trans(slice *[]int)  {
	//slice[0]=30
    *slice=append(*slice,10)
	}

12. 内存空间分布

栈区数据区内存空间由系统管理
new在堆区申请内存空间

	var arr *[3]int= new([3]int)
	arr[0]=10
	(*arr)[0]=20
	fmt.Println(*arr)  //[20 0 0]

13.aop

Go语言本身不支持AOP(面向切面编程),但可以通过一些库和框架来实现该功能。常用的库包括go-aop和GoAop。GoAop比较新,但使用起来比较简单,支持常规拦截器和环绕拦截器等。

除了AOP外,还有其他一些解决方案可以实现基于切面的编程,例如使用“装饰器”模式,将函数或方法作为参数传递,并在某些前提下进行修改。建议根据实际需求来选择最适合的解决方案。

14.new和make

new 用于分配内存,返回对应类型的指针并分配好对应类型的空间;make 则是分配并初始化内置(切片、映射和通道)类型
new 分配返回的是指针,即类型 *Type。make 返回引用,即 Type;
new 分配的空间被清零,即new生成的变量的指针的值为对应类型的0值。make 分配空间后,会进行初始化;

c := new(chan int)
这种方式创建的是一个指向channel的指针,需要使用*操作符来解引用才能得到channel实例。通常不建议使用这种方式创建通道,因为它不能直接使用,需要进行额外的初始化操作才能使用,容易导致错误

正常使用

func main() {
    ch := make(chan int) // 使用make()来初始化一个channel
    go func() {
        ch <- 10 // 将10写入channel中
    }()
    result := <- ch // 从channel中接收值并赋给result变量
    fmt.Println(result)
}

使用new会有死锁问题

## new函数分配了一块内存空间,但没有初始化channel,所以在给channel发送和接收数据时会出现nil channel导致的死锁错误
func main() {
    ch := new(chan int) // 初始化一个channel
    go func() {
        *ch <- 10 // 给channel发送一个值
    }()
    result := <- *ch // 从channel中接收一个值
    fmt.Println(result)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值