二. Go(Go基础知识)
一. Go基础语法
变量的定义
使用var关键字,可以放在函数内,或者直接放在包内,使用var()集中定义变量,使用:=
可以简化定义,但是只能在函数内使用
package main
import "fmt"
//没有全局变量的概念,使用var()这种写法/
var (
a = 1
b = 2
)
func variableZeroValue() {
var a int
var b int
fmt.Printf("%d %q\n", a, b)
}
func variableInitialValue() {
var a, b int = 1, 2
fmt.Println(a + b)
}
func variableTypeDeduction() {
var a, b, c, d = 1, false, "2", true
//可以简写 := /
e := "111"
b = true
fmt.Println(a, b, c, d, e)
}
func main() {
fmt.Println("hello world")
variableZeroValue()
variableInitialValue()
variableTypeDeduction()
fmt.Println(a + b)
}
内建变量类型
- bool,string(布尔,字符串)
- (u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr 加u有符号整数 不加u无符号整数 如果不规定长度 int 还是 int8 还是int32 默认按照操作系统位数 来决定
- byte,rune byte字节 8位,rune是4个字节相当于java里的char 但是char是一个字节考虑到国际化原因rune竟可能能放下各种编码 32位 Unicode是2个字节 16位 utf-8是三个字节 24位。
- float32,float64,complex64,complex128 浮点数32位和64位,复数 complex64 实部和虚部 分别是 32位 (var a complex64=3 +4i) 128位以此类推。
强制类型转换
类型转换必须是强制的
func trigonometric() {
a, b := 3, 4
var c int
c = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)
}
常量与枚举
const数值可作为各种类型使用(var c int = int(math.Sqrt(aa + bb)))由于常亮没指定类型 它可以自己转换类型。
枚举类型
注意自增公式的使用
func enums() {
const (
cpp = 1
java = 2
scala = 3
lua = 4
)
fmt.Println(cpp, java, scala, lua)
const (
b = 1 << (10 * iota)
kb
mb
gb
tb
)
fmt.Println(b, kb, mb)
}
条件语句
if
注意:if 可以像其他语言中的for循环一样的表达式进行判断
package main
import (
"fmt"
"io/ioutil"
)
func main() {
const filename = "D:\\玩游戏和安装软件的.txt"
//从源码中能够看到 ,"io/ioutil 下面的 ioutil.ReadFile方法会返回两个值,[]byte 文件内容,error错误信息/
contents, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", contents)
}
//if 可以像其他语言中的for循环一样的表达式进行判断/
if contents, err := ioutil.ReadFile(filename); err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", contents)
}
}
switch
GO语言和其他语言对比switch会自动有break,如果我们需要执行后面的 case,可以使用 fallthrough
Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,才使用Go中引入的Exception处理:defer, panic, recover。
func eavl(a, b int, op string) int {
var re int
switch op {
case "+":
return a + b
case "*":
return a * b
default:
panic("不支持的运算符" + op)
}
return re
}
注意可以没有expression
func grade(a int) int {
var re = 0
switch {
case a <= 0:
return 1
case a > 0 && a <= 100:
return a
case a > 100:
return 100
default:
fmt.Println("其他的....")
}
return re
}
for
注意for实现while的用法
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func sumTen() int {
sum := 0
for a := 10; a > 0; a-- {
sum += a
}
return sum
}
func converToBin(n int) string {
var re string = ""
for ; n > 0; n /= 2 {
lsb := n % 2
re = strconv.Itoa(lsb) + re
}
return re
}
func readFile(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
} else {
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
}
func whileLike() {
for {
fmt.Println("死循环")
time.Sleep(100)
}
}
func main() {
fmt.Println(sumTen())
fmt.Println(converToBin(13))
readFile("D:\\玩游戏和安装软件的.txt")
whileLike()
}
函数
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
func div(a, b int) (int, int) {
return a / b, a % b
}
func div1(a, b int) (q, r int) {
return a / b, a % b
}
//函数式编程/
func apply(op func(int, int) int, a, b int) int {
pointer := reflect.ValueOf(op).Pointer()
name := runtime.FuncForPC(pointer).Name()
fmt.Println(name, a, b)
return op(a, b)
}
//返回多个参数/
func main() {
fmt.Println(div(13, 3))
q, r := div1(13, 3)
fmt.Println(q, r)
fmt.Println(apply(func(i int, i2 int) int {
return int(math.Pow(float64(i), float64(i2)))
}, 3, 4))
}
可变参数
func sunArgs(values ...int) int {
sum := 0
for i := range values {
sum += values[i]
}
return sum
}
指针
值传递和引用传递?
Go语言只有值传递一种....这一块我在Java那里就没怎么搞清楚,后来学了点scala似乎搞清楚了,主要在于情景的应用
func swap(a,b int) {
b,a = a,b
}
func swap1(a,b *int) {
*b,*a = *a,*b
}
二. 内建容器
数组(golang 一般不用的,数组是值传递)
package main
import (
"fmt"
)
//数组是值类型
func changeArray(arr [3]int) {
arr[0] = 100
for k, v := range arr {
fmt.Println(k, v)
}
}
func changeArray1(arr *[3]int) {
arr[0] = 100
for k, v := range arr {
fmt.Println(k, v)
}
}
func main() {
var arr1 [5]int
fmt.Println(arr1)
arr2 := [3]int{1, 2, 3}
fmt.Println(arr2)
var arr3 = [...]int{2, 4, 6}
fmt.Println(arr3)
var grid [5][5]int
fmt.Println(grid)
//遍历
for k, v := range arr2 {
fmt.Println(k, v)
}
changeArray(arr2)
for k, v := range arr2 {
fmt.Println(k, v)
}
changeArray1(&arr2)
for k, v := range arr2 {
fmt.Println(k, v)
}
}
切片👍
???下面两个又什么区别,为什么这种写法[]是值传递的....(教材有误)
arr := []int{0, 1, 2, 3, 4, 5, 6, 7}
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
解决:区分数组的声明和切片的声明方式 当使用字面量来声明切片时,其语法与使用字面量声明数组非常相似。二者的区别是:如果在 [] 运算符里指定了一个值,那么创建的就是数组而不是切片。只有在 [] 中不指定值的时候,创建的才是切片。看下面的例子:
// 创建有 3 个元素的整型数组
myArray := [3]int{10, 20, 30}
// 创建长度和容量都是 3 的整型切片
mySlice := []int{10, 20, 30}
package main
import "fmt"
func take(arr []int) {
arr[3] = 100
}
func main() {
arr := []int{0, 1, 2, 3, 4, 5, 6, 7}
s := arr[2:6]
fmt.Println(s)
s1 := arr[2:]
fmt.Println(s1)
s2 := s[1:3]
fmt.Println(s2)
take(arr)
fmt.Println(arr)
fmt.Println(s1)
fmt.Println(s2)
arr1 := []int{0, 1, 2, 3, 4, 5, 6, 7}
s11 := arr1[2:6]
s22 := s11[3:5]
fmt.Printf("len=%d cap=%d slice=%v\n", len(s11), cap(s11), s11)
fmt.Printf("len=%d cap=%d slice=%v\n", len(s22), cap(s22), s22)
}
slice的扩展
slice可以向后扩展,但是不可以向前扩展
向slice添加元素
添加元素时如果超越cap,系统就会重新分配更大的底层数组
由于值传递的关系,必须接收append的返回值
package main
import "fmt"
func show(arr []int) {
fmt.Println(len(arr), cap(arr))
}
func main() {
var arr []int
for i := 0; i < 100; i++ {
show(arr)
arr = append(arr, 2*i)
}
fmt.Println(arr)
}
Go 语言切片(Slice) | 菜鸟教程 (runoob.com)
Golang 入门 : 切片(slice) 👍
切片之所以被称为切片,是因为创建一个新的切片,也就是把底层数组切出一部分。通过切片创建新切片的语法如下:
slice[i:j]
slice[i:j:k]
其中 i 表示从 slice 的第几个元素开始切,j 控制切片的长度(j-i),k 控制切片的容量(k-i),如果没有给定 k,则表示切到底层数组的最尾部。(看一下切片的扩展)
map
在向map中存储元素的时候,会将每个key经过hash运算,根据运算得到的hash值选择合适的hash bucket(hash桶),让后将各个key/value存放到选定的hash bucket中。如果一来,整个map将根据bucket被细分成很多类别,每个key可能会交叉地存放到不同的bucket中。所以,map中的元素是无序的,遍历时的顺序是随机的,即使两次以完全相同的顺序存放完全相同的元素,也无法保证遍历时的顺序。由于要对key进行hash计算选择hash bucket,所以map的key必须具有唯一性,否则计算出的hash值相同,将人为出现hash冲撞。在访问、删除元素时,也类似,都要计算key的hash值,然后找到对应的hash bucket,进而找到hash bucket中的key和value。Go中的map是一个指针,它的底层是数组,而且用到了两个数组,其中一个更底层的数组用于打包保存key和value。
package main
import "fmt"
func main() {
m1 := map[int]string{
1: "上海",
2: "北京",
}
m2 := make(map[string]string)
var m3 = map[int]string{}
fmt.Println(m1, m2, m3)
for _, v := range m1 {
fmt.Println(v)
}
if v, Exist := m1[10]; Exist {
fmt.Println(v)
} else {
fmt.Println("not exist")
}
delete(m1, 1)
var _, OK = m1[1]
fmt.Println(OK)
}
func main() {
mf := map[int]func() int{
1: func() int { return 10 },
2: func() int { return 20 },
5: func() int { return 50 },
}
fmt.Println(mf) // 输出函数的指针
a := mf[1]() // 调用某个分支的函数
println(a)
}
寻找最长不含有重复字符的子串
package main
import "fmt"
func take_num(st string) int {
//字符对应的最新索引
m := map[byte]int{}
start := 0
st_lenth := 0
bytes := []byte(st)
for i, ch := range bytes {
// ok && lastI >= start ,ok是因为在map中存在的话就更新,与此同时lastI >= start保证了小的ch值不能小于start
if lastI, ok := m[ch]; ok && lastI >= start {
start = lastI + 1
}
if i-start+1 > st_lenth {
st_lenth = i - start + 1
}
m[ch] = i
}
return st_lenth
}
func main() {
fmt.Println(take_num("abcbod"))
}
三. 面对对象
结构体和方法
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
// 自定义工厂方法
func createTreeNode(value int) *treeNode {
return &treeNode{value: value}
}
//为结构定义方法,显示定义和命名方法的接收者
func (node treeNode) print() {
fmt.Println(node.value)
}
//值传递
func (node treeNode) setValue(value int) {
node.value = value
}
func (node *treeNode) setValue1(value int) {
node.value = value
}
// 树的遍历
func (node *treeNode) traverse() {
if node == nil {
return
}
node.left.traverse()
node.print()
node.right.traverse()
}
func main() {
var r treeNode
r = treeNode{value: 1}
var _ = treeNode{left: new(treeNode)}
r.left = &treeNode{}
r.right = &treeNode{2, nil, nil}
r.right.left = new(treeNode)
fmt.Println(r)
r.left.left = createTreeNode(3)
r.print()
fmt.Println(r.left.left)
r.setValue(100)
fmt.Println(r.value) //还是3
r.setValue1(100)
fmt.Println(r.value) //100
r.traverse()
}
值接收者和指针接收者
- 要改变内容必须要使用指针接收者
- 结构过大也考虑指针接收者
- 一致性问题:如果有指针接收者,最好都是指针接收者
- 值/指针接收者均可接收值/指针
封装
扩展已有类型
- 定义别名
- 使用组合
在 Go 中,通过在结构体内嵌套结构体,可以实现组合,组合的典型例子就是博客帖子。每一个博客的帖子都有标题、内容和作者信息。使用组合可以很好地表示它们
golang的组合
使用内嵌来扩展已有结构
这块有点混乱....改天再看看吧...
Go学习:使用内嵌来扩展已有类型