第一节
声明
go语言是一个强类型语言,每一个变量都有自己的变量类型
go语言字符串是内置类型,可以直接通过+号拼接,也能用=号来比较两个字符串,(大部分运算符都和c和c++很类似)
在golong中有两种声明变量
第一种是
var num = value
这个var一般会自己推导变量的类型,也可以用int double这种
第二种是
f := value
下面看常量
常量是把var改成const即可
const s = 6000
在golong中常量没有确定的类型,是根据上下文会自动确定类型
if和else
if后面是不能加括号的,也就是c和c++中把括号给去掉,并且是必须加上大括号的,如果加上括号,在系统中也会把括号给去掉
if 7?2 == 0{
fmt.Println(" 7 is even ")
}
循环
只有唯一的for循环,如果for循环里面什么都没写的的话就是死循环
for {
break;
}
正常模板
for i := 7 ; i < 9 ;i++{
fmt.Println(j)
}
switch
swich需要注意两点,第一点是与c++不同,每一个case后面是不用回加continue , 第二点是 case后面可以当作if else 用表达式来判断
t := time.now()
switch{
case t.Hour() < 12:
fmt,Print("1")
default:
fmt,Print("2")
}
数组
声明 var a [ 5 ] int
a[4] = 100
fmt.Println(a[4],len(a))
或者
b := [5]int{1,2,3,4,5}
fmt,Print(b)
二维数组的声明是
var two [2] [3] int
for i := 0 ;i < 2;i++{
for j := 0;j < 3;j++{
two[i][j] = i + j
}
}
fmt,Print("2d : ", two)
切片
在golong中很少会用到数组,一般都是切片,他就是相当于是一长度可以增加的数组
1 :make声明
s := make([]string, 3) 长度和数量 s[0] = "a" s[1] = "b" s[2] = "c"
2 :append增加
s = append(s, "d") s = append(s, "e", "f") fmt.Println(s) // [a b c d e f]
3:copy复制
c := make([]string, len(s)) copy(c, s) fmt.Println(c) // [a b c d e f]
4:指定输出
fmt.Println(c) // [a b c d e f] fmt.Println(s[2:5]) // [c d e] fmt.Println(s[:5]) // [a b c d e] fmt.Println(s[2:]) // [c d e f]
map(哈希)
make声明
make(map [ key的类型]value的类型 )
m := make(map[string]int) m["one"] = 1 m["two"] = 2 fmt.Println(m) // map[one:1 two:2] fmt.Println(len(m)) // 2 fmt.Println(m["one"]) // 1 fmt.Println(m["unknow"]) // 0
可以用delete函数删除
delete(m, "one")
可以用ok来判断是否含有key
r, ok := m["unknow"] fmt.Println(r, ok) // 0 false
golong里面的map是完全无序的,所以遍历的时侯不会按插入顺序输出
range
函数
golong与其他语言不同的是
1:他的参数变量类型是后置的
2 :返回值类型放在参数的后面,并且可以有多个返回值类型
func add(a int, b int) int { return a + b }
func exists(m map[string]string, k string) (v string, ok bool) { v, ok = m[k] return v, ok }
第二个括号是返回值的类型,返回以一个类型是string 第二个是bool类型
指针
golong的指针不同于c和c++,操作是十分有限的
func add2(n int) { n += 2 } func add2ptr(n *int) { *n += 2 } func main() { n := 5 add2(n) fmt.Println(n) // 5 add2ptr(&n) fmt.Println(n) // 7 }
跟c语言的一样
结构体
结构体的声明
type user struct { name string password string }
在赋值过程中,如果是用结构体里面的名字来赋值,没有被赋值的名字默认为:如果是数据类型就是0,如果是字符串就是空,如下面代码第三行的 password是空
a := user{name: "wang", password: "1024"} b := user{"wang", "1024"} c := user{name: "wang"}
也可以用指针对结构体进行修改,也能解决对某些大结构体拷贝的开销
func checkPassword(u user, password string) bool { return u.password == password } func checkPassword2(u *user, password string) bool { return u.password == password }
错误处理
在golong里面查询错误习惯用一个单独的返回值来传递信息,go里边不同于Java那样,他可以很清晰的知道哪个函数发生了错误,并且可以用简单的if和else去处理错误
我们可以在函数返回值类型中添加一个err(意为error),意思就是这个函数可能发生错误,在函数实现的时候可以用if判断,如果函数没有发生错误就返回第一个return ,如果发生错误就是第二个了
func findUser(users []user, name string) (v *user, err error) { for _, u := range users { if u.name == name { return &u, nil } } return nil, errors.New("not found") }
调用函数的方式
u, err := findUser([]user{{"wang", "1024"}}, "wang") if err != nil { fmt.Println(err) return } fmt.Println(u.name) // wang
字符串操作
fmt.Println(strings.Contains(a, "ll")) // true fmt.Println(strings.Count(a, "l")) // 2 fmt.Println(strings.HasPrefix(a, "he")) // true fmt.Println(strings.HasSuffix(a, "llo")) // true fmt.Println(strings.Index(a, "ll")) // 2 fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo fmt.Println(strings.Repeat(a, 2)) // hellohello fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo fmt.Println(strings.Split("a-b-c", "-")) // [a b c] fmt.Println(strings.ToLower(a)) // hello fmt.Println(strings.ToUpper(a))
字符串格式化
在标准库中有许多字符串的格式化,用的最多的是
fmt.Println()
n := 123 p := point{1, 2} fmt.Println(s, n) // hello 123
还有fmt.Printf()
fmt.Printf("s=%v\n", s) // s=hello fmt.Printf("n=%v\n", n) // n=123 fmt.Printf("p=%v\n", p) // p={1 2} fmt.Printf("p=%+v\n", p) // p={x:1 y:2} fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
这与c语言的printf函数很相似,但是所有的变量都用%v来表示,通过+和#可以做到更加精确
JSON操作
时间处理
数字解析
就是把字符串解析成一个整数
在字符串和数字之间的转换都都是在strconv包中的
我们可以用ParseInt 和 ParseFLoat来解析字符串
f, _ := strconv.ParseFloat("1.234", 64) fmt.Println(f) // 1.234
ParseInt 有 三个参数 ,第一个就是字符串,第二个就是进制,比如输入10就是10进制,如果输入的是0的话就是自动去推测,第三个就是精度,如果填写64,就是64位的精度
n, _ := strconv.ParseInt("111", 10, 64) fmt.Println(n) // 111-
我们也可用Atoi来快速的把一个字符串转化为一个10进制的数字
n2, _ := strconv.Atoi("123") fmt.Println(n2) // 123
也可以用Itoa 来快速的把一个数字转化为字符串
如果输入不合法的话返回值会返回错误
n2, err := strconv.Atoi("AAA") fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
进程信息
进程是操作系统中一个重要的概念,它代表了一个正在运行的程序实例。每个进程都有自己的内存空间、文件描述符、寄存器状态等资源。操作系统通过进程管理来调度这些资源,确保多个进程能够并发执行。
进程的基本概念
- 进程ID(PID)
:每个进程都有一个唯一的标识符,称为进程ID(PID)。PID是操作系统用来识别和管理进程的唯一标识。
- 父进程ID(PPID)
:每个进程都有一个父进程,父进程的PID称为PPID。当一个进程创建另一个进程时,创建者就是父进程,被创建的就是子进程。
- 进程状态
:进程在执行过程中会经历不同的状态,如:
新建(New):进程正在被创建。
就绪(Ready):进程已经准备好运行,等待CPU调度。
运行(Running):进程正在CPU上执行。
阻塞(Blocked):进程因为等待某些事件(如I/O操作)而暂停执行。
终止(Terminated):进程已经完成执行或被终止。
- 进程控制块(PCB)
:操作系统为每个进程维护一个数据结构,称为进程控制块(PCB)。PCB包含了进程的所有信息,如PID、PPID、进程状态、寄存器状态、内存映射等。
进程的创建与终止
- 进程创建
:
fork():在Unix/Linux系统中,fork()系统调用用于创建一个新的进程。新进程是原进程的副本,拥有相同的内存映像、打开的文件等。
exec():exec()系统调用用于加载一个新的程序到当前进程的内存空间中,替换原有的程序。
- 进程终止
:
进程间通信(IPC)
进程间通信(IPC)是多个进程之间交换数据和信息的机制。常见的IPC机制包括:
- 管道(Pipe):一种半双工的通信方式,数据只能单向流动。
- 命名管道(Named Pipe):类似于管道,但可以在不相关的进程之间使用。
- 消息队列(Message Queue):进程可以通过消息队列发送和接收消息。
- 共享内存(Shared Memory):多个进程可以访问同一块内存区域,实现数据共享。
- 信号量(Semaphore):用于进程同步,防止多个进程同时访问共享资源。
- 套接字(Socket):用于网络通信,可以在不同主机上的进程之间进行通信。
进程调度
操作系统通过进程调度算法来决定哪个进程获得CPU时间。常见的调度算法包括:
- 先来先服务(FCFS):按照进程到达的顺序进行调度。
- 短作业优先(SJF):优先调度运行时间最短的进程。
- 优先级调度:根据进程的优先级进行调度。
- 时间片轮转(Round Robin):每个进程被分配一个时间片,时间片用完后,进程被放回就绪队列。
- 多级反馈队列:结合了时间片轮转和优先级调度,根据进程的行为动态调整优先级。
进程与线程
线程是进程中的一个执行单元,一个进程可以包含多个线程。线程共享进程的内存空间和资源,但每个线程有自己的寄存器状态和栈。线程的创建和销毁比进程更轻量,因此更适合高并发的场景。
进程监控与管理
操作系统提供了多种工具来监控和管理进程,如:
ps:显示当前系统中的进程信息。
top:实时显示系统中各个进程的资源使用情况。
htop:top的增强版,提供更丰富的功能和更友好的界面。
kill:用于终止进程。
nice:调整进程的优先级。