Go中slice作为参数传递的一些“坑”

https://juejin.im/post/5a9f543a6fb9a028cb2d2b91

看明白了上面的文章,下面的例子基本也就明白了

 

package main

import "fmt"

func main() {
	a := []int{1,2,3}
	abc(a)
	fmt.Println(a)
}
func abc(a []int) {
	a[0] = 2 //修改后还是原来的a
	a = append(a, 4) // 此a非原a,使用append导致了重新分配内存地址(存储空间不足,系统自动分配一块新的足够大的内存地址,此时a的物理内存地址已经发行了变化,并将原来a的值copy一份到新的内存地址,所以这里修改的只是新内存地址的值,原来内存地址的值并没有改变),试着删除这行运行一次再看结果
	fmt.Println(a)
	
	a[0] = 7 // 新a,因为上面执行了append
	fmt.Println(a)
	
	fmt.Printf("\n===\n")
}

解释:

golang中string rune byte 三者的关系

在Golang中 string 底层是用byte字节数组存储的,并且是不可以修改的。

例如

s:="Go编程"
fmt.Println(len(s)) //输出结果应该是8因为中文字符是用3个字节存的(2+3*2=8)。
fmt.Printf("%d", len(string(rune('编')))) //经测试一个汉字确实占用3个字节,所以结果是3

如果想要获得字符个数的话,需要先转换为rune切片再使用内置的len函数

fmt.Println(len([]rune(s))) // 结果就是4了。

所以用string存储unicode的话,如果有中文,按下标是访问不到的,因为你只能得到一个byte。 要想访问中文的话,还是要用rune切片,这样就能按下表访问。

总结:
rune 能操作任何字符
byte 不支持中文的操作

示例:https://blog.haohtml.com/archives/14903

[翻译]理解 GO 语言的内存使用

许多人在刚开始接触 Go 语言时,经常会有的疑惑就是“为什么一个 Hello world 会占用如此之多的内存?”。Understanding Go Lang Memory Usage 很好的解释了这个问题。不过“简介”就是“简介”,更加深入的内容恐怕要读者自己去探索了。另外,文章写到最后,作者飘了,估计引起了一些公愤,于是又自己给自己补刀,左一刀,右一刀……

————翻译分隔线————

理解 Go 语言的内存使用

2014年12月22日,星期一

温馨提示:这仅是关于 Go 语言内存的简介,俗话说不入虎穴、焉得虎子,读者可以进行更加深入的探索。

大多数 Go 开发者都会尝试像这样简单的 hello world 程序:

package main

import (
"fmt"
"time"
)

func main() {
fmt.Println("hi")

time.Sleep(30 * time.Second)
}

然后他们就完全崩溃了。

high_mem-300x38

这个笔记本也只有 16 G 内存!

虚拟内存 vs 常驻内存

Go 管理内存的方式可能与你以前使用的方式不太一样。它会在一开始就保留一大块 VIRT,而 RSS 与实际内存用量接近。

RSS 和 VIRT 之间有什么区别呢?

VIRT 或者虚拟地址空间大小是程序映射并可以访问的内存数量。

RSS 或者常驻大小是实际使用的内存数量。 Continue reading

Profiling Go Programs

转自:http://blog.golang.org/profiling-go-programs (需翻墙)

The Go Blog

Profiling Go Programs

24 June 2011

At Scala Days 2011, Robert Hundt presented a paper titled Loop Recognition in C++/Java/Go/Scala. The paper implemented a specific loop finding algorithm, such as you might use in a flow analysis pass of a compiler, in C++, Go, Java, Scala, and then used those programs to draw conclusions about typical performance concerns in these languages. The Go program presented in that paper runs quite slowly, making it an excellent opportunity to demonstrate how to use Go's profiling tools to take a slow program and make it faster.

By using Go's profiling tools to identify and correct specific bottlenecks, we can make the Go loop finding program run an order of magnitude faster and use 6x less memory.(Update: Due to recent optimizations of libstdc++ in gcc, the memory reduction is now 3.7x.) Continue reading

golang中并发实例

package main

import (
	"fmt"
	//"runtime"
	"os"
	"runtime/pprof" // 引用pprof package
	"time"
)

func main() {
	f, _ := os.Create("profile_file")
	pprof.StartCPUProfile(f)     // 开始cpu profile,结果写到文件f中
	defer pprof.StopCPUProfile() // 结束profile

	startTime := time.Now().Second()
	//runtime.GOMAXPROCS(runtime.NumCPU())

	ch := make(chan int, 100)
	quit := make(chan bool)

	go read(ch, quit)

	for i := 0; i < 2000; i++ {
		ch <- i
		fmt.Println(i)
	}

	quit <- true

	fmt.Println("\r\n====MAIN END====\r\n")
	endTime := time.Now().Second()

	fmt.Println(startTime)
	fmt.Println(endTime)
	fmt.Println("用时:", endTime-startTime, "秒")
}

func read(ch chan int, quit chan bool) {
	for {
		select {
		case value := <-ch:
			fmt.Print("----", value, "----")
		case <-quit:
			break
		}

	}
}

 

在Golang中使用json

由于要开发一个小型的web应用,而web应用大部分都会使用json作为数据传输的格式,所以有了这篇文章。

包引用

import (
    "encoding/json"
    "github.com/bitly/go-simplejson" // for json get
)

用于存放数据的结构体

type MyData struct {
    Name   string    `json:"item"`
    Other  float32   `json:"amount"`
}

这里需要注意的就是后面单引号中的内容。

`json:"item"`

这个的作用,就是Name字段在从结构体实例编码到JSON数据格式的时候,使用item作为名字。算是一种重命名的方式吧。 Continue reading

golang的json操作

package main
 
import (
    "encoding/json"
    "fmt"
    "os"
)
 
type ConfigStruct struct {
    Host              string   `json:"host"`
    Port              int      `json:"port"`
    AnalyticsFile     string   `json:"analytics_file"`
    StaticFileVersion int      `json:"static_file_version"`
    StaticDir         string   `json:"static_dir"`
    TemplatesDir      string   `json:"templates_dir"`
    SerTcpSocketHost  string   `json:"serTcpSocketHost"`
    SerTcpSocketPort  int      `json:"serTcpSocketPort"`
    Fruits            []string `json:"fruits"`
}
 
type Other struct {
    SerTcpSocketHost string   `json:"serTcpSocketHost"`
    SerTcpSocketPort int      `json:"serTcpSocketPort"`
    Fruits           []string `json:"fruits"`
}
 
func main() { 
    jsonStr := `{"host": "http://localhost:9090","port": 9090,"analytics_file": "","static_file_version": 1,"static_dir": "E:/Project/goTest/src/","templates_dir": "E:/Project/goTest/src/templates/","serTcpSocketHost": ":12340","serTcpSocketPort": 12340,"fruits": ["apple", "peach"]}`
 
    //json str 转map
    var dat map[string]interface{}
    if err := json.Unmarshal([]byte(jsonStr), &dat); err == nil {
        fmt.Println("==============json str 转map=======================")
        fmt.Println(dat)
        fmt.Println(dat["host"])
    }
 
    //json str 转struct
    var config ConfigStruct
    if err := json.Unmarshal([]byte(jsonStr), &config); err == nil {
        fmt.Println("================json str 转struct==")
        fmt.Println(config)
        fmt.Println(config.Host)
    }
 
    //json str 转struct(部份字段)
    var part Other
    if err := json.Unmarshal([]byte(jsonStr), &part); err == nil {
        fmt.Println("================json str 转struct==")
        fmt.Println(part)
        fmt.Println(part.SerTcpSocketPort)
    }
 
    //struct 到json str
    if b, err := json.Marshal(config); err == nil {
        fmt.Println("================struct 到json str==")
        fmt.Println(string(b))
    }
 
    //map 到json str
    fmt.Println("================map 到json str=====================")
    enc := json.NewEncoder(os.Stdout)
    enc.Encode(dat)
 
    //array 到 json str
    arr := []string{"hello", "apple", "python", "golang", "base", "peach", "pear"}
    lang, err := json.Marshal(arr)
    if err == nil {
        fmt.Println("================array 到 json str==")
        fmt.Println(string(lang))
    }
 
    //json 到 []string
    var wo []string
    if err := json.Unmarshal(lang, &wo); err == nil {
        fmt.Println("================json 到 []string==")
        fmt.Println(wo)
    }
}

参考第三方json库 simplejson 的用法:http://blog.haohtml.com/archives/16851

转自:http://www.cnblogs.com/go-ios/p/3906251.html

golang中的md5的用法

代码

package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
)

func main() {
	// md5 加密的第一种方法
	srcData := []byte("iyannik0215")
	cipherText1 := md5.Sum(srcData)
	fmt.Printf("md5 encrypto is \"iyannik0215\": %x \n", cipherText1)

	// md5 加密的第二种方法
	hash := md5.New()
	hash.Write(srcData)
	cipherText2 := hash.Sum(nil)
	hexText := make([]byte, 32)
	hex.Encode(hexText, cipherText2)
	fmt.Println("md5 encrypto is \"iyannik0215\":", string(hexText))
}
# 执行结果
md5 encrypto is "iyannik0215": b6b20c73e6bc53bc691a6bb559cf9ca9
md5 encrypto is "iyannik0215": b6b20c73e6bc53bc691a6bb559cf9ca9

不同

解释一下两种加密方式的不一样之处.
第一种加密方法:
第一种加密方法所调用的函数

//Source file src/crypto/md5/md5.go
19	// The size of an MD5 checksum in bytes.
20	const Size = 16

130	// Sum returns the MD5 checksum of the data.
131	func Sum(data []byte) [Size]byte {
132		var d digest
133		d.Reset()
134		d.Write(data)
135		return d.checkSum()
136	}

func Sum(data []byte) [Size]byte
其 [Size]byte 是固定死的.所以说第一种方法返回的是 16长度的数组(无法转string类型,需使用第二种加密方法)
第二种加密方法:

//Source file src/crypto/md5/md5.go
50	// New returns a new hash.Hash computing the MD5 checksum.
51	func New() hash.Hash {
52		d := new(digest)
53		d.Reset()
54		return d
55	}
// 这里只放了函数签名部分, 关于函数具体内容这里就不详细复制了.
51	func New() hash.Hash {}
61	func (d *digest) Write(p []byte) (nn int, err error) {}
90	func (d0 *digest) Sum(in []byte) []byte {}

这里使用 func New() hash.Hash {} 函数进行生成对象.
使用 func (d *digest) Write(p []byte) (nn int, err error) {} 方法进行写入要加密的数据.
使用 func (d0 *digest) Sum(in []byte) []byte {} 方法进行数据的加密 看其返回值.
[]byte 可见使用第二种方式加密返回的是 []byte 类型的切片.

转:http://openskill.cn/article/206?utm_source=tuicool&utm_medium=referral

golang中chan实例

package main

import "fmt"

func main() {
 data := make(chan int) // 数据交换队列
 exit := make(chan bool) // 退出通知

go func() {
 for d := range data { // 从队列迭代接收数据,直到 close 。
   fmt.Println(d)
 }

 fmt.Println("recv over.")
 exit <- true // 发出退出通知。
}()

data <- 1 // 发送数据。
data <- 2
data <- 3

close(data) // 关闭队列。

fmt.Println("send over.")

<-exit // 等待退出通知。
}

输出结果:

1
2
3
send over.
recv over.

而如果将上面与 exit chan有关的三行删除掉,则结果为:

1
2
3
send over.

缺少了“recv over."一行,为什么?

大家可以  time.Sleep(time.Second * 2) 来自己分析一下