编程之久除了算法和数据结构,什么也不属于我们。
编程就是算法和数据结构,算法和数据结构是编程的灵魂。
编程中最没用的东西是源代码,最有用的东西是算法和数据结构。
算法和数据结构是程序的第一秘诀,缺之算法和数据结构是编程的最大原因。
算法和数据结构就是编程的一个重要部分,你若失掉了算法和数据结构,你就把一切都失掉了。
尽管少写那么多代码,但省下来的时间又在哪里呢?
代码是程序员的朋友,虽然没有热情,但是非常忠实。
当你还不能写出自己满意的程序时,你就不要去睡觉。
有些代码不应该被忘记,也没有源代码不应该被记住。
对代码不满足,是任何真正有天才的程序员的根本特征。
有编过程的人的代码,比那些无知的人使用的软件更有价值。
编程是一种美德,是促使一个人不断向上发展的一种原动力。
程序员的一生时间90%是用在编程上,而剩余的10%是活在世界上。
程序员之所以犯错误,不是因为他们不懂,而是因为他们自以为什么都懂。
调试的错误就是编程给你最好的东西,因为在每个错误上面都标志着前进的一步。
假如编程易懂得,那么程序员就不会热情地写出注释,也不会有得到编程的快乐。
代码是最为耐心、最能忍耐和最令人愉快的伙伴,在任何艰难困苦的时刻,它都不会抛弃你
day3
1.类型转换
1.1 简单的类型转换
// 浮点数
a := 5.0
// 转换为int类型
b := int(a)
Go允许在底层结构相同的两个类型之间互转。例如:
// IT类型的底层是int类型
type IT int
// a的类型为IT,底层是int
var a IT = 5
// 将a(IT)转换为int,b现在是int类型
b := int(5)
// 将b(int)转换为IT,c现在是IT类型
c := IT(b)
不是所有数据类型都能转换的,例如字母格式的string类型"abcd"转换为int肯定会失败
低精度转换为高精度时是安全的,高精度的值转换为低精度时会丢失精度。例如int32转换为int16,float32转换为int
这种简单的转换方式不能对int(float)和string进行互转,要跨大类型转换,可以使用strconv包提供的函数
strconv包提供了字符串与简单数据类型之间的类型转换功能。可以将简单类型转换为字符串,也可以将字符串转换为其它简单类型。
1.2 strconv
这个包里提供了很多函数,大概分为几类:
字符串转int:Atoi()
int转字符串: Itoa()
ParseTP类函数将string转换为TP类型:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。因为string转其它类型可能会失败,所以这些函数都有第二个返回值表示是否转换成功
FormatTP类函数将其它类型转string:FormatBool()、FormatFloat()、FormatInt()、FormatUint()
AppendTP类函数用于将TP转换成字符串后append到一个slice中:AppendBool()、AppendFloat()、AppendInt()、AppendUint()
- int转换为字符串:Itoa()
// Itoa(): int -> string
println("a" + strconv.Itoa(32)) // a32
- string转换为int:Atoi()
// Atoi(): string -> int
i,_ := strconv.Atoi("3")
println(3 + i) // 6
// Atoi()转换失败
i,err := strconv.Atoi("a")
if err != nil {
println("converted failed")
}
1.3 strings
result := strings.HasPrefix(url,"http://")
if !result{
// 返回一个格式化的字符串,并不输出
url = fmt.Sprintf("http://%s",url)
}
// 以/ 结尾
result := strings.HasSuffix(path,"/")
// 返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换所有old子串
str := "hello world abc"
result := strings.Replace(str,"world","you",1)
//返回new_str字符重复次数
strings.count(old_str,new_str)
// 字符串重复
result = strings.Repeat(str,2)
// hello world abchello world abc
//字符小写
result = strings.ToLower(str)
fmt.Println(result)
//字符大写
result = strings.ToUpper(str)
fmt.Println(result)
field_result := strings.Fields(str)
// 数组 [hello world abc]
split_result := strings.Split(str,"o")
fmt.Println(split_result)
// 去除元素 [hell w rld abc]
a := "hahaha"
b := "hehehe"
c := strings.Join([]string{a,b},",")
fmt.Println(c)
// hahaha,hehehe 字符串连接
1.4 println 与printf 的区别
Println 有自动换行操作 而Printf没有 但是Printf有占位符的处理
package main
import ("fmt")
func main() {
var test1 int = 1
var test2 int = 2
fmt.Println("哈哈哈%d",test1) //哈哈哈%d 1 有空格
fmt.Println("哈哈哈",test1) //哈哈哈 1
fmt.Printf("哈哈哈%d\n",test1) //哈哈哈1
fmt.Printf("哈哈哈%d%d\n",test1,test2) //哈哈哈12
}
2.指针
3.函数参数传递
4.defer
当一个方法中有多个defer时, defer会将要延迟执行的方法“压栈”,当defer被触发时,将所有“压栈”的方法“出栈”并执行。所以defer的执行顺序是LIFO的。
example15
// defer
func read() {
lock.Lock()
defer lock.Unlock()
if i==5{
return
}
if i==10{
return
}
//数据库的连接 最后释放
conn := openDatabase()
defer conn.Close()
}
5.匿名函数
example16
func test(a,b int) int {
result := func(a1,b1 int)int {
return a1+b1
}(a,b)
// return result(a,b)
return result
}
6.rune函数
rune是Go语言中一种特殊的数据类型,它是int32的别名,几乎在所有方面等同于int32,用于区分字符值和整数值
在Golang中string类型的底层是通过byte数组实现的,在unicode编码中,中文字符占两个字节,而在utf-8编码中,中文字符占三个字节而Golang的默认编码正是utf-8.
如果想要获得真实的字符串长度而不是其所占用字节数,有两种方法实现
-
方法一:
使用unicode/utf-8包中的RuneCountInString方法str := "hello 世界" fmt.Println("RuneCountInString:", utf8.RuneCountInString(str))
-
方法二:
将字符串转换为rune类型的数组再计算长度str := "hello 世界" fmt.Println("rune:", len([]rune(str)))
7.课后题 九九表,完数,回文,记录字符数量,两数相加
99
//九九乘法表
func table() {
for i := 0; i <= 9; i++ {
for a := 1; a <= i; a++ {
fmt.Printf("%d*%d=%d\t", i, a, i*a)
}
fmt.Println()
}
}
回文
//仅字符 中文len(三个字符)
func huiwen(str string) bool {
for i := 0; i < len(str); i++ {
if i == len(str)/2 {
break
}
last := len(str) - i - 1
if str[i] != str[last] {
return false
}
}
return true
}
// 中英文都可以
func huiwen1(str string) bool {
t := []rune(str)
fmt.Printf(string(t), "\n")
for i, v := range t {
if i == len(t)/2 {
break
}
last := len(t) - i - 1
if t[i] != t[last] {
return false
}
fmt.Printf("%v-%v,%d\n", i, v, len(string(v)))
}
return true
}
func main() {
var str string
fmt.Scanf("%s",&str)
if huiwen1(str){
fmt.Println("yes")
}else {
fmt.Println("no")
}
完数
func perfect(n int) bool {
var sum int
for i := 1; i < n; i++ {
if n%i == 0 {
sum = sum + i
}
}
return sum == n
}
func process(n int) {
for i := 1; i < n; i++ {
if perfect(i) == true {
fmt.Println(i)
}
}
}
func main() {
var n int
fmt.Scanf("%d",&n)
process(n)
记录字符数量
//返回多值加()
func num_str(str string) (word, space, number, other int) {
t := []rune(str)
for _, v := range t {
switch {
case v >= 'a' && v <= 'z':
fallthrough
case v >= 'A' && v <= 'Z':
word++
case v == ' ':
space++
case v >= '0' && v <= '9':
number++
default:
other++
}
}
return
}
func main() {
reader := bufio.NewReader(os.Stdin)
result,_,err:=reader.ReadLine()
if err !=nil{
fmt.Println("read is error")
return
}
wc,sc,nc,oc:=num_str(string(result))
fmt.Printf("word %d\n space %d\n number %d\n other %d\n",wc,sc,nc,oc)
}
两数相加
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func multi(str1, str2 string) (result string) {
if len(str1) == 0 && len(str2) == 0 {
result = "0"
return
}
var index1 = len(str1) - 1
var index2 = len(str2) - 1
var left int
for index1 >= 0 && index2 >= 0 {
c1 := str1[index1] - '0'
c2 := str2[index2] - '0'
sum := int(c1) + int(c2) + left
if sum >= 10 {
left = 1
} else {
left = 0
}
c3 := (sum % 10) + '0'
result = fmt.Sprintf("%c%s", c3, result)
index1--
index2--
}
for index1 >= 0 {
c1 := str1[index1] - '0'
sum := int(c1) + left
if sum >= 10 {
left = 1
} else {
left = 0
}
c3 := (sum % 10) + '0'
result = fmt.Sprintf("%c%s", c3, result)
index1--
}
for index2 >= 0 {
c1 := str2[index2] - '0'
sum := int(c1) + left
if sum >= 10 {
left = 1
} else {
left = 0
}
c3 := (sum % 10) + '0'
result = fmt.Sprintf("%c%s", c3, result)
index2--
}
if left == 1 {
result = fmt.Sprintf("1%s", result)
}
return
}
func main() {
reader := bufio.NewReader(os.Stdin)
result, _, err := reader.ReadLine()
if err != nil {
fmt.Println("read from console err:", err)
return
}
strSlice := strings.Split(string(result), "+")
if len(strSlice) != 2 {
fmt.Println("please input a+b")
return
}
strNumber1 := strings.TrimSpace(strSlice[0])
strNumber2 := strings.TrimSpace(strSlice[1])
fmt.Println(multi(strNumber1, strNumber2))
}
day4
1.Go语言中异常处理painc()和recover()的用法
Go语言提供了recover内置函数,前面提到,一旦panic,逻辑就会走到defer那,那我们就在defer那等着,调用recover函数将会捕获到当前的panic(如果有的话),被捕获到的panic就不会向上传递了,于是,世界恢复了和平。你可以干你想干的事情了。
package main
import "fmt"
func main(){
defer func(){ // 必须要先声明defer,否则不能捕获到panic异常
fmt.Println("c")
if err:=recover();err!=nil{
fmt.Println(err) // 这里的err其实就是panic传入的内容,55
}
fmt.Println("d")
}()
f()
}
func f(){
fmt.Println("a")
panic(55)
fmt.Println("b")
fmt.Println("f")
}
2. 内置函数 new make 递归函数
example2:
new:它返回的永远是类型的指针,指向分配类型的内存地址。
make:也是用于内存分配的,但是和new不同,它只用于chan、map以及切片的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
递归:一个大问题可以拆分成很多个小问题时,可以用递归
3. makeSuffix
func makeSuffix(suffix string) func(string) string {
f := func(name string) string {
if strings.HasSuffix(name, suffix) == false {
return name + suffix
}
return name
}
return f
func main() {
f1 := makeSuffix(".bmp")
fmt.Println(f1("test"))
fmt.Println(f1("pic"))
4. 线程与协程
xiecheng:
https://blog.csdn.net/TDCQZD/article/details/82684636
func fab(n int) {
var a []int
a = make([]int, n)
fmt.Println(a)
a[0] = 1
a[1] = 1
for i := 2; i < n; i++ {
a[i] = a[i-1] + a[i-2]
}
for _, v := range a {
fmt.Println(v)
}
}
5.数组
example6:
func testArray2() {
var a [2][5]int = [...][5]int{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}
for row, v := range a {
for col, v1 := range v {
fmt.Printf("(%d,%d)=%d ", row, col, v1)
}
fmt.Println()
}
}
//(0,0)=1 (0,1)=2 (0,2)=3 (0,3)=4 (0,4)=5
//(1,0)=6 (1,1)=7 (1,2)=8 (1,3)=9 (1,4)=10
6.go cap和len的区别
首先要搞清楚容量和长度的区别:
容量是指底层数组的大小,长度指可以使用的大小
容量的用处在哪?在与当你用 appen d扩展长度时,如果新的长度小于容量,不会更换底层数组,否则,go 会新申请一个底层数组,拷贝这边的值过去,把原来的数组丢掉。也就是说,容量的用途是:在数据拷贝和内存申请的消耗与内存占用之间提供一个权衡。
而长度,则是为了帮助你限制切片可用成员的数量,提供边界查询的。所以用 make 申请好空间后,需要注意不要越界【越 len 】
func testSlice() {
var a[]int = []int{1,2,3,4,5}
s :=a[1:]
fmt.Println(a[1])
fmt.Printf("s=%p, a[1]=%p,len()=%d,cap=%d\n",s,&a[1],len(s),cap(s)) //内存地址不变
// s=0xc00000e2d8, a[1]=0xc00000e2d8,len()=4,cap=4
s = append(s, 10)// 越界,内存变化
s = append(s, 10)
s = append(s, 10)
fmt.Println(s)
fmt.Printf("s=%p, a[1]=%p,len()=%d,cap=%d\n",s,&a[1],len(s),cap(s)) //内存地址变
// s=0xc00000c2c0, a[1]=0xc00000e2d8,len()=7,cap=8
}
7.字符串添加
func testModifyString() {
s:="我hello world"
s1 := []rune(s) //转为rune类型 不能用byte
fmt.Println(s1)
// [104 101 108 108 111 32 119 111 114 108 100]
s1[1]='0'
fmt.Println(s1)
// [104 48 108 108 111 32 119 111 114 108 100]
fmt.Println(string(s1))
// 我h0llo world
}
8.排序
sort.Ints(a)
sort.Strings(a)
sort.Float64s(a)
var a=[]int{3,2,6,111,9}
sort.Ints(a)
b:=sort.SearchInts(a[:], 2)//查找默认排序后的 2下标
map排序需遍历,然后sort排序
9.map函数
//a[]=""
func testMap() {
var a map[string]string=map[string]string{
"key":"values",
}
//a=make(map[string]string,10)//分配内存空间
a["abc"]="qwer"
a["abc"]="qwer"
a["y"]="qwer"
fmt.Println("test1",a)
}
func testMap2() {
a:=make(map[string]map[string]string,100)
a["key1"]=make(map[string]string)
a["key1"]["key2"] ="abc"
a["key1"]["key3"] ="abc"
a["key1"]["key4"] ="abc"
a["key1"]["key5"] ="abc"
fmt.Println(a)
// map[key1:map[key2:abc key3:abc key4:abc key5:abc]]
}
func testMap3() {
a:=make(map[string]map[string]string,100)
_,ok :=a["zhangsan"]
if !ok{
a["zhangsan"]=make(map[string]string)
}
a["zhangsan"]["password"] ="123456"
a["zhangsan"]["nickname"]="pangpang"
fmt.Println(a)
// map[zhangsan:map[nickname:pangpang password:123456]]
}
// a[""][""]=""
func testMap4() {
a:=make(map[string]map[string]string,100)
a["key1"]=make(map[string]string)
a["key1"]["key2"] ="abc"
a["key1"]["key3"] ="abc"
a["key1"]["key4"] ="abc"
a["key1"]["key5"] ="abc"
a["key2"]=make(map[string]string)
a["key2"]["key4"] ="abc"
a["key2"]["key5"] ="abc"
for k,v :=range a["key1"]{
fmt.Println(k,v)
}
delete(a,"key1")
fmt.Println(a)
fmt.Println(len(a))
//key2 abc
//key3 abc
//key4 abc
//key5 abc
//map[key2:map[key4:abc key5:abc]]
//1
}
// a[]=int
func testMap5() {
var a[]map[int]int
a =make([]map[int]int,5) //分配内存空间
fmt.Println(a)
if a[0]==nil{
a[0]=make(map[int]int)
}
a[0][10]= 100
fmt.Println(a)
//[map[10:100] map[] map[] map[] map[]]
}
day5
1. 排序、链表、二叉树、接口
2.自定义类型的方法
package main
import "fmt"
type integer int
func (p integer) print() {
fmt.Println("p is ", p)
}
func (p *integer) set(b integer) {
*p = b
}
type Student struct {
Name string
Age int
Score int
sex int
}
func (p *Student) init(name string, age int, score int) {
p.Name = name
p.Age = age
p.Score = score
fmt.Println(p)
}
func (p Student) get() Student {
return p
}
func main() {
var stu Student
stu.init("stu", 10, 200)
stu1 := stu.get()
fmt.Println(stu1)
var a integer
a = 100
a.print()
a.set(1000)
a.print()
}
//&{stu 10 200 0}
//{stu 10 200 0}
//p is 100
//p is 1000
day6
接口与反射
package main
import "fmt"
type Carer interface {
GetName() string
Run()
DiDi()
}
type Test interface {
Hello()
}
type BMW struct {
Name string
}
func (p *BMW) GetName() string {
return p.Name
}
func (p *BMW) Run() {
fmt.Printf("%s is running\n", p.Name)
}
func (p *BMW) DiDi() {
fmt.Printf("%s is didi\n", p.Name)
}
func (p *BMW) Hello() {
fmt.Printf("hello, i'm %s \n", p.Name)
}
type BYD struct {
Name string
}
func (p *BYD) GetName() string {
return p.Name
}
func (p *BYD) Run() {
fmt.Printf("%s is running\n", p.Name)
}
func (p *BYD) DiDi() {
fmt.Printf("%s is didi\n", p.Name)
}
func main() {
var car Carer
var test Test
fmt.Println(car)
bmw := &BMW{
Name: "BMW",
}
car = bmw
car.Run()
test = bmw
test.Hello()
byd := &BYD{
Name: "BYD",
}
car = byd
car.Run()
}
example9:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Student struct {
Name string `json:"student_name"`
Age int
Score float32
Sex string
}
func (s Student) Print() {
fmt.Println("---start----")
fmt.Println(s)
fmt.Println("---end----")
}
func (s Student) Set(name string, age int, score float32, sex string) {
s.Name = name
s.Age = age
s.Score = score
s.Sex = sex
}
func TestStruct(a interface{}) {
tye := reflect.TypeOf(a)
val := reflect.ValueOf(a)
kd := val.Kind()
if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
fmt.Println("expect struct")
return
}
num := val.Elem().NumField()
val.Elem().Field(0).SetString("stu1000")// 改变值
for i := 0; i < num; i++ {
// Elem()指针改为变量
fmt.Printf("%d %v %v\n", i, val.Elem().Field(i),val.Elem().Field(i).Kind())
}
fmt.Printf("struct has %d fields\n", num)
tag := tye.Elem().Field(0).Tag.Get("json")
fmt.Printf("tag=%s\n", tag)
numOfMethod := val.Elem().NumMethod()
fmt.Printf("struct has %d methods\n", numOfMethod)
var params []reflect.Value
val.Elem().Method(0).Call(params)
}
func main() {
var a Student = Student{
Name: "stu01",
Age: 18,
Score: 92.8,
}
fmt.Println(a)
result, _ := json.Marshal(a)//变为json格式
fmt.Println("json result:", string(result))
TestStruct(&a) //传地址
fmt.Println(a)
}
day7
负载均衡算法
随机
package balance
import (
"errors"
"math/rand"
)
func init() {
RegisterBalancer("random", &RandomBalance{})
}
type RandomBalance struct {
}
func (p *RandomBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
if len(insts) == 0 {
err = errors.New("No instance")
return
}
lens := len(insts)
index := rand.Intn(lens)
inst = insts[index]
return
}
轮播
package balance
// 轮播
import (
"errors"
)
func init() {
RegisterBalancer("roundrobin", &RoundRobinBalance{})
}
type RoundRobinBalance struct {
curIndex int //当前机器索引
}
func (p *RoundRobinBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
if len(insts) == 0 {
err = errors.New("No instance")
return
}
lens := len(insts)
if p.curIndex >= lens {
p.curIndex = 0
}
inst = insts[p.curIndex]
//假如有三台机器,加了一台越界 4/3 取余数 1
p.curIndex = (p.curIndex + 1) % lens
return
}
命令行参数
os.Args
func main() {
fmt.Printf("len of args:%d\n", len(os.Args))
for i, v := range os.Args {
fmt.Printf("args[%d]=%s\n", i, v)
}
}
go run main.go 655 655
args[0]=C:\Users\ADMINI~1\AppData\Local\Temp\go-build201241730\b001\exe\main.exe
args[1]=655
args[2]=655
json
example9
struct
package main
import (
"encoding/json"
"fmt"
)
type User struct {
UserName string `json:"username"`
NickName string `json:"nickname"`
Age int
Birthday string
Sex string
Email string
Phone string
}
func testStruct() (ret string, err error) {
user1 := &User{
UserName: "user1",
NickName: "上课看似",
Age: 18,
Birthday: "2008/8/8",
Sex: "男",
Email: "mahuateng@qq.com",
Phone: "110",
}
data, err := json.Marshal(user1)
if err != nil {
err = fmt.Errorf("json.marshal failed, err:", err)
return
}
ret = string(data)
return
}
func test() {
data, err := testStruct()
if err != nil {
fmt.Println("test struct failed, ", err)
return
}
var user1 User
//反序列成结构体
err = json.Unmarshal([]byte(data), &user1) //字符串转为字符数组 传指针
if err != nil {
fmt.Println("Unmarshal failed, ", err)
return
}
fmt.Println(user1)
}
func main() {
test()
test2()
}
map
func testMap() (ret string, err error) {
var m map[string]interface{}
m = make(map[string]interface{})
m["username"] = "user1"
m["age"] = 18
m["sex"] = "man"
data, err := json.Marshal(m)
if err != nil {
err = fmt.Errorf("json.marshal failed, err:", err)
return
}
ret = string(data)
return
}
func test2() {
data, err := testMap()
if err != nil {
fmt.Println("test map failed, ", err)
return
}
var m map[string]interface{}
// map里面插数据 不需要传地址 改变map本身 需要传地址
err = json.Unmarshal([]byte(data), &m)
if err != nil {
fmt.Println("Unmarshal failed, ", err)
return
}
fmt.Println(m)
}
day8
文件操作
func main() {
file ,err :=os.Open("D:/abc.txt")
if err !=nil{
fmt.Println(err)
return
}
defer file.Close()
reader := bufio.NewReader(file)
for{
data,prefix,err :=reader.ReadLine()
if err == io.EOF {
break
}
if !prefix {
fmt.Printf("%s\n", string(data))
}
}
}
goroute原理
并发、并行
进程、线程、协程
多协程数据交互
//读少写多 互斥 读多写少 读写锁
//m 为全局变量 需加锁
var(
m =make(map[int]uint64)
lock sync.Mutex
)
type task struct {
n int
}
func calc(t *task) {
var sum uint64
sum = 1
for i := 1; i < t.n; i++ {
sum = sum * uint64(i)
}
lock.Lock()
m[t.n]=sum
lock.Unlock()
}
func main() {
for i := 0; i < 1000; i++ {
t := &task{n: i}
go calc(t)
}
time.Sleep(3*time.Second)
lock.lock()
for k,v :=range m{
fmt.Printf("%d = %v\n" ,k,v)
}
lock.Unlock()
}