GO 语言基础学习记录

一:声明变量

在golang语言中声明变量的方式

package main

import "fmt"

func main() {
        var a int = 3  //关键字 var + 变量名 + 变量指定类型 = 变量值        

        var b int        //关键字 var + 变量名 + 变量指定类型(注意:当变量没赋值时是按照变量指定类型的默认值进行赋值,如 【var b int】最后输出的就是int类型的0 而【var b bool】则会输出bool类型的false )

        var c = 4        //关键字 var + 变量名 = 变量值(注意:当变量未设置类型则会根据变量值自行补充,如【var c = 4】则c的类型为int 而【var c = "hello"】c的类型则为string)

        var d, e int = 1, 2  //这是在第一个声明的基础上进行多个变量声明

        var f, g int              //这是在第二个声明基础上进行多个变量声明  

        var h, i = 7, 8        //这是在第三个声明基础上进行多个变量声明

        //输出

        fmt.Println(a, b, c, d, e, f, g, h, i)

        //输出的值为 3 0 4 1 2 0 0 7 8
}

注意:在方法中设置变量的时候,一定要在方法体中用到,否则会报错(如果 var c int 在方法中却没有使用,则运行程序会报错!)!! -- go的全局变量不限制,仅校验方法中的变量

go中除了用 var 关键字声明的变量外,还提供了 := 的方式声明未声明过的变量。

package main

import "fmt"

func main() {
       a := 3 

       b := "hellow"

       c, d := 8, "word"

        //输出

        fmt.Println(a, b, c, d)

        //输出的值为 3 hellow 8 word
}

注意::= 只能用于声明 未被声明过的变量( 如声明 var a int  = 3   后再 a := 4  就会报错)

二:声明常量

常量的声明可以参考变量声明的第一部分-此处省略

const a int = 3 //关键字 const + 常量名 + 常量类型 = 常量值

注意:常量在方法中声明不校验是否调用、

除了上面的常量声明方式外,常量还可用作枚举

package mainimport "fmt"func main() {const (Unknown = 0Female = 1Male = 2)//输出fmt.Println(Unknown, Female, Male)//输出值为 0 1 2
}

在常量声明时,可以引入“unsafe” 包使用 函数计算表达式,注意:必须是系统内置函数

package main

import "fmt"
import "unsafe"


func main() {
        const (
                a = "abc"
                b = len(a)
                c = unsafe.Sizeof(a)
        )
        const e string = "abg"
        const f int = len(a)
        const g = unsafe.Sizeof(a)

        //输出
        fmt.Println(a, b, c, e, f, g)

        //输出值为 abc 3 16 abg 3 16
}

 相对于常量声明中 枚举类型 有个 iota 用法 ,就是 从0开始依次递增  

package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

三、运算符

go的运算符和其他编程语言基本一致

+(加)、-(减)、*(乘)、/(除)、%(取余数)、++(自增)、--(自减)、==(相等)、!=(不等)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)、&&(与)、||(或)、!(非)等等

这里着重记录一下 位运算 和 其他运算符 (了解即可,日常业务中很少用到)

位运算符:&(二进制相与)、|(二进制相或)、^(二进制相异)、<<(二进制左移)、>>(二进制右移)

package main

import "fmt"

func main() {

   var a uint = 60      /* 60 = 0011 1100 */  
   var b uint = 13      /* 13 = 0000 1101 */
   var c uint = 0          

   c = a & b    /* 12 = 0000 1100 */ //二进制相与,当二进制码对应位都为1时记录为1
   fmt.Printf("第一行 - c 的值为 %d\n", c )

   c = a | b     /* 61 = 0011 1101 */ //二进制相或,当二进制码对应位有一位为1时记录为1
   fmt.Printf("第二行 - c 的值为 %d\n", c )

   c = a ^ b     /* 49 = 0011 0001 */ //二进制相异,当二进制码对应位值不同时记录为1
   fmt.Printf("第三行 - c 的值为 %d\n", c )

   c = a << 2   /* 240 = 1111 0000 */ //二进制左移,将左侧丢弃,右侧填补为0,<<2就是丢弃两位
   fmt.Printf("第四行 - c 的值为 %d\n", c )

   c = a >> 2   /* 15 = 0000 1111 */ //二进制右移,将右侧丢弃,左侧填补为0
   fmt.Printf("第五行 - c 的值为 %d\n", c )
}

 其他运算符:&(获取变量存储地址)、*(指针变量)

package main

import "fmt"

func main() {
        var a int = 4  
        var ptr *int
        /* & 和 * 运算符实例 */
        ptr = &a /* 'ptr' 包含了 'a' 变量的地址 */
        fmt.Printf("a 的值为 %d\n", a);  //输出a变量的值 4
        fmt.Printf("a 的值为 %d\n", &a); //输出a变量的变量存储地址,能粗浅理解为数据库的索引
        fmt.Printf("*ptr 为 %d\n", *ptr); //输出的是指针变量下的值  4
        fmt.Printf("ptr 为 %d\n", ptr);  //输出指针变量的存储地址
}

在go中也有其他语言的  if、if...else..、switch、等。

也有:for 循环和嵌套,有 break、continue、goto语句。

注意:在go中没有while循环

 四、函数、方法声明和调用

package main

import "fmt"

func main() {
        var a, b int = 4,5
        var c int
        var s string
        c = sum(a,b)
        s = fmt.Sprintf("获取a+b=%d",c)
        fmt.Println(s)
}

func sum(x int,y int) int{   //声明函数 关键字func + 函数名称 + 函数参数和参数类型 + 返回类型
        return x+y
}

注意:声明函数的时候,必须设定参数类型和返回值类型!

 这里记录一下  函数多个返回值 和 函数闭包(匿名函数) 的用法

package main

import "fmt"

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}


func swap(x, y string) (string, string) { //设定两个string类型的返回值
   return y, x
}

package main

import "fmt"

func main() {
    // 定义一个匿名函数并将其赋值给变量add
    add := func(a, b int) int {
        return a + b
    }


    // 调用匿名函数
    result := add(3, 5)
    fmt.Println("3 + 5 =", result)

    // 在函数内部使用匿名函数
    multiply := func(x, y int) int {
        return x * y
    }

    product := multiply(4, 6)
    fmt.Println("4 * 6 =", product)

    // 将匿名函数作为参数传递给其他函数
    calculate := func(operation func(int, int) int, x, y int) int {
        return operation(x, y)
    }

    sum := calculate(add, 2, 8)
    fmt.Println("2 + 8 =", sum)

    // 也可以直接在函数调用中定义匿名函数
    difference := calculate(func(a, b int) int {
        return a - b
    }, 10, 4)
    fmt.Println("10 - 4 =", difference)
}

再记录一下 go 中的方法

package main

import (
   "fmt"  
)

/* 定义结构体 */
type Circle struct {
          radius float64
}

func main() {
          var c1 Circle
          c1.radius = 10.00
          fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
          //c.radius 即为 Circle 类型对象中的属性
          return 3.14 * c.radius * c.radius
}

注意:从上面的例子中我们可以看出,在go中 方法和函数是不同的。方法在定义的时候会在 func 关键字后面  方法名的前面 设置一个接收器( c Circle) 该接收器可在方法中调用

五、变量作用域

函数方法外面的是全局变量,方法或函数内的则是局部变量,局部变量优先级大于全局变量。局部变量除非作为参数传入另一个方法或函数中,否则两个方法或函数中的局部变量不能共用。

六、数组

在go中初始化数组,需要明确个数和类型

var  a [10]int   //初始化数组 关键字 var + 数组名 + [数组元素个数]数组元素类型

var  a = [5]int{1,2,3,4,5} //初始化数组 a 并赋值

a := [5]int{1,2,3,4,5} //省略关键字 var 初始化数组 a 并赋值

var a = [...]int{1,2,3} //省略数组元素个数,通过"..."程序会自动通过赋值确定元素个数

a := [...]int{1,2,3} //和上面同理

var a []int   //设置空切片a  注意:不指定长度的数组都是切片,第七点记录切片

a := []int{}  //设置空切片a

 多维数组也同理  var a [][]int 初始化即可 

package main

import "fmt"

func main() {
        // Step 1: 创建数组
        values := [][]int{}   //创建二维空数组

        // Step 2: 使用 append() 函数向空的二维数组添加两行一维数组
        row1 := []int{1, 2, 3}
        row2 := []int{4, 5, 6}
        values = append(values, row1)
        values = append(values, row2)

        // Step 3: 显示两行数据
        fmt.Println("Row 1")
        fmt.Println(values[0])
        fmt.Println("Row 2")
        fmt.Println(values[1])

        // Step 4: 访问第一个元素
        fmt.Println("第一个元素为:")
        fmt.Println(values[0][0])
}

 七、切片

相较于数组的长度不可改变,go还提供了切片的类型也可以称之为 动态数组,即它的长度不固定,可以直接追加元素提升切片的元素数

通过make()函数来创建切片

var slice []type = make([]type, len)   //注意:len只是定义切片的初始长度 可以为0

slice := make([]type, len)

如:

slice1 := make([]int,0)  //这行代码创建了个长度为0 的slice1 切片

除了用make() 函数来创建切片外

slice2 := []int{} 和 var slice2 []int  也是初始化了一个切片

对于数组来说,切片除了不用固定长度这一个优点外,还有一个切片赋值的功能

package main

import "fmt"

func main() {
        arr :=[]int {1,2,3 }  //初始化一个切片 a  里面有三个值
        s := arr[0:2]          //将切片下标0-2 的值 赋值给s
        fmt.Println(s)        //输出 [1 2] 

        fmt.Println(len(arr)) //
        fmt.Println(cap(arr)) //

}

切片除了通过[:]来获取指定下标的值,由于切片有索引,所以go很多内置函数都可作用于切片上

如:len()//获取切片长度  cap() //计算容量获得切片最大长度

八、range的用法

当需要循环数组、切片、集合等数据时,可以用for + range 的关键字来遍历。

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
for i, v := range pow {     //应用range时,会直接将循环中的key值提供给i,value值提供给v(i,v是变量类型,可以设置成你熟悉的变量名 如:k,v  也可以)
                fmt.Printf("2**%d = %d\n", i, v)
        }
}

除了将 pow 的值完全按照 key-value 的形式完全赋值给 i,v 外,如果只想要key,则可以省略v 如:for i := range pow{  或者用 _ 代替 如  for  i,_  := range  pow { 

当然,如果只想要value 不要key时也可以用 _ 代替 如:   for _,v := range pow{

注意://range也可以用来枚举 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身

 九、map的用法

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的

在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 ""。

Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。

// 创建一个空的 Map
m := make(map[string]int)   

// 创建一个初始容量为 10 的 Map
m := make(map[string]int, 10)

// 使用字面量创建 Map
m := map[string]int{"apple": 1,"banana": 2,"orange": 3,
}
// 获取键值对
v1 := m["apple"]     //map 就和 php中的数组对象类似,用值的时候直接 变量[key值] 即可
v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值

Map很像php 中的数组对象类型,但是Map是引用类型,要注意改变其中一个值时 其他引用过Map的变量都会更改

package main

import "fmt"

func main() {
        s := map[string]string{    //初始化一个map数据
                "one" : "one",
                "two" : "two",
                "three" : "three",
        }
        c := s                                //将 s 赋值给 c
        a := s["two"]                     
        b := s["two"]
        a = "for"
        fmt.Println(a, b, s, c)  //输出值 for two map[one:one three:three two:two]  map[one:one three:three two:two]
        s["two"] = "fiv"
        fmt.Println(a, b, s, c) //for two map[one:one three:three two:fiv] map[one:one three:three two:fiv]
}

从上面的示例可以看出,当将整个map类型的s赋值给c时,修改s 的值,c同样会变化!

delete() 函数可以删除map中的值 delete(map变量,需要删除的key值)

十、变量类型转换

1、数值类型转换

var a float64 = 3.7415926     //定义float64类型a为3.7415926
var b int        = int(a)              //将a转变成int类型赋值给b

fmt.Println(a, b)                     //输出结果 a=3.7415926     b=3   从float转化为int时,会直接舍去小数点后的值

 注意:go 不支持隐式转换类型,比如 :

package main
import "fmt"func main() {  var a int64 = 3var b int32b = afmt.Printf("b 为 : %d", b)
}

会报错

cannot use a (type int64) as type int32 in assignment
cannot use b (type int32) as type string in argument to fmt.Printf

但是如果改成 b = int32(a) 就不会报错了:

package main
import "fmt"func main() {  var a int64 = 3var b int32b = int32(a)fmt.Printf("b 为 : %d", b)
}
2、字符串类型转换
var str string = "10"        //定义字符串str
var num int                  //初始化int类型num
num, _ = strconv.Atoi(str)   //将字符串转换为num的数据类型,其中 _ 位置取的是转换时的错误信息,如果想查看错误信息则需

var msg error                                //定义error类型 msg

num,msg  = strconv.Atoi(str)        //通过 msg 获取转换失败的信息

或者可以用下面方法直接获取:

number, msg = strconv.Atoi(str)   //没有错误时 msg为nil

注意:使用strconv.Atoi() 函数时,要引入  strconv 包

3.接口类型转换

接口类型转换有两种情况:类型断言类型转换

类型断言用于将接口类型转换为指定类型:

value.(T)

 其中 value 是接口类型的变量, T 是要转换成的类型。

如果类型断言成功,它将返回转换后的值和一个布尔值,这个布尔值表示转换是否成功。

package main

import "fmt"

func main() {
    var i interface{} = "Hello, World"                  //定义接口变量i
    str, ok := i.(string)                                        //将i类型断言为字符串类型 返回转换后的值和断言结果
    if ok {        //类型断言成功
        fmt.Printf("'%s' is a string\n", str)
    } else {      //类型断言失败
        fmt.Println("conversion failed")
    }
}

类型转换用于将一个接口类型的值转换为另一个接口类型:

T(value)

T 是目标接口类型,value 是要转换的值。

注意:在类型转换中,我们必须保证要转换的值和目标接口类型之间是兼容的,否则编译器会报错。

package main

import "fmt"

type Write interface { //定义接口Write 接口参数为 []byte类型数据 返回值为 int 和 error类型
        Write([]byte)(int,error)
}

type WriteString struct { //定义结构体WriteString 结构体属性 str 为字符串类型
        str string
}


func (ws WriteString) Write(data []byte)(int, error){ 
        ws.str += string(data)
        return len(ws.str) , nil
}

func main(){
        var w WriteString
        ss := "hellow_Word!"
        sb := []byte(ss)
        fmt.Println(w.Write(sb))
}

 十一、go实现并发

Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。

package main

import (
        "fmt"
        "time"
)

func say(s string) {
        for i := 0; i < 5; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
        }
}

func main() {
        go say("world")
        say("hello")
}

//输出的 world 和 hello 出现的顺序并不固定,也从侧面证明了 使用go关键字后确实 两次方法调用确实没有先后,是处于两条并发线程中

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

package main

import "fmt"

func sum(s []int, c chan int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 sum 发送到通道 c
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}

        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收
        fmt.Println(x, y, x+y)
}

 目前我认为通道的作用 就是用于等待时常 可以同时获取到 两个goroutine 的值。

注意:x和y的值不一定是按照执行代码先后时间来分配的,也就是说x有可能获得第二个结果

 如下面的代码,只要多执行几次,总会获得 *d, *e, *f  依旧会输出 1, 2, 3 的情况 或者 其中几个值是sum 运行后的值,从而证明了 并发并不是执行完goroutine 之后再进行下面代码的执行。

package main

import "fmt"

func sum(s []int, c *int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        *c = sum
        fmt.Println(" sum中:",*c,"------\n")
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}
        a,b,c := 1,2,3
        d, e, f := &a, &b, &c
        go sum(s[:len(s)/2], d)
        go sum(s[len(s)/2:], e)
        go sum(s[2:len(s)-2], f)
        fmt.Println(" 变量值 ",*d, *e, *f,"------\n")
}

或者我提供另一个佐证   执行这段代码时,会沉睡,直至x和y 接收到结果

package main

import (
        "fmt"
        "time"
)

func sum(s []int, c chan int) {
        sum := 0
        time.Sleep(10 * time.Second) //沉睡十秒
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 sum 发送到通道 c
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}
        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收
        fmt.Println(x, y, x+y)
}

学习时借助查看 菜鸟教程

网址:Go 语言教程 | 菜鸟教程 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/763125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯】第15届蓝桥杯青少组stema选拔赛C++中高级真题答案(20240310)

一、选择题 第 1 题 第 2 题 表达式1000/3的结果是( A )。 A.333 B.333.3 C.334 D.333.0 第 3 题 下列选项中&#xff0c;判断a等于1并且b等于1正确的表达式是( B )。 A.!((a!1)&&(b!1)) B.!((a!1)||(b!1)) C.!(a1)&&(b1) D.(a1)&&(b1) 【解析】 A…

面试(一)

一. 说一下进程和线程的区别&#xff1f; (1)进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位。 (2)线程是进程的一部分&#xff0c;一个线程只能属于一个进程&#xff0c;一个进程可以有多个线程&#xff0c;但至少有一个线程。 (3)进程有自己独立地址空间&a…

我的春招求职面经

智能指针在面试时经常被问到&#xff0c;最近自己也在写&#xff0c;有一点思考&#xff0c;于是找到了这样一个题目&#xff0c;可以看看&#xff0c;上面这个代码有什么问题&#xff1f;留言区说出你的答案吧&#xff01; 最后分享一下之前的实习->春招->秋招等文章汇总…

可以完成80%的数据分析工作的20个Pandas函数

Pandas 是数据科学社区中使用最广泛的库之一&#xff0c;它是一个强大的工具&#xff0c;可以进行数据操作、清理和分析。本文将提供最常用的 Pandas 函数以及如何实际使用它们的样例。我们将涵盖从基本数据操作到高级数据分析技术的所有内容&#xff0c;到本文结束时&#xff…

huggingface的transformers训练bert

目录 理论 实践 理论 https://arxiv.org/abs/1810.04805 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是一种自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;由Google在2018年提出。它是基于Transformer模型的预训练方法…

使el-table通过操控鼠标滚轮横向滚动

1.创建directive文件夹&#xff0c;里面创建directive.js文件 import Vue from vue;Vue.directive(scroll-x,{inserted:function(el){let domClass el.getAttribute(class)if(domClass.indexOf(el-table)<0){return false}const scrollDiv el;if(scrollDivnull){return fa…

OpenCV基于边缘的分割详解

OpenCV 中基于边缘的分割是一种常见的图像分割技术&#xff0c;它利用图像中的边缘信息来进行分割。边缘通常是图像中灰度值变化较大的区域&#xff0c;因此可以作为物体之间的分界线。以下是基于边缘的分割在 OpenCV 中的详细介绍&#xff1a; Canny 边缘检测&#xff08;Cann…

YOLOv9有效改进|CVPR2023即插即用的到残差注意力机制(轻量化注意力机制)Inverted Residual Mobile Block

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 在YOLOv9中加入CVPR2023即插即用的到残差注意力机制。 二、模块详解 2.1 模块简介 Inverted Residual Mobile Block结合了倒置残差块…

JavaEE企业开发新技术3

目录 2.11 Method的基本操作-1 文字性概念描述 代码&#xff1a; 2.12 Method的基本操作-2 2.13 Method的基本操作-3 2.14 数组的反射操作-1 文字性概念&#xff1a; 代码&#xff1a; 2.15 数组的反射操作-2 学习内容 2.11 Method的基本操作-1 文字性概念描述 Me…

SSM整合Springboot

1.0 概述 1.1 持久层&#xff1a; DAO层&#xff08;mapper&#xff09; DAO层&#xff1a;DAO层主要是做数据持久层的工作&#xff0c;负责与数据库进行联络的一些任务都封装在此 DAO层的设计首先是设计DAO的接口&#xff0c; 然后在spring-mapper.xml的配置文件中定义此接…

“低代码+平台”:驱动企业数字化转型与创新的新引擎

“低代码平台”作为一种新兴的软件开发范式&#xff0c;正逐渐成为企业快速响应市场变化、优化业务流程、提升数字化水平的重要手段。它的价值在于&#xff0c;将传统软件开发的复杂性大大降低&#xff0c;赋予了非技术人员或轻量级开发者快速构建应用的能力&#xff0c;并能灵…

【vue-小知识】var、let 和 const之间的区别

文章目录 结论1、重复定义变量名var&#xff1a;允许重复定义变量名let和const&#xff1a;不可以重复定义变量名 2、修改值var&#xff1a;允许修改值let&#xff1a;允许修改值const&#xff1a;不允许修改值&#xff0c;会报错 3、变量提升var : 支持变量提升let和const&…

【黑马程序员】Python多任务

文章目录 多进程多进程使用流程导入包Process进程类说明 获取进程编号目的常用操作 获取进程名进程注意点进程之间不共享全局变量主进程会等待子进程结束之后再结束设置守护主进程 多线程threading模块线程注意点线程之间执行是无序的主线程会等待所有的子线程执行结束在结束线…

Docker compose()

1.概述 是 Docker 官方提供的一款开源工具&#xff0c;主要用于简化在单个主机上定义和运行多容器 Docker 应用的过程。它的核心作用是容器编排&#xff0c;使得开发者能够在一个统一的环境中以声明式的方式管理多容器应用的服务及其依赖关系。 也就是说Docker Compose是一个用…

吃瓜Grok大模型

段子区 今年当地时间2月29日晚&#xff0c;马斯克闹出来一件大事——正式起诉OpenAI和Sam Altman&#xff0c;并要求OpenAI 恢复开源GPT-4等模型。国际流量大师我只付服马斯克和川宝!&#xff01; 当大家觉得这扯皮的故事就此结束后&#xff0c;马斯克“不负众望”的整了一个大…

负载均衡原理及算法

负载均衡指把用户请求分摊到不同服务器处理&#xff0c;提高系统的并发性和可靠性。 可由专门的软件&#xff08;更便宜&#xff09;和硬件&#xff08;性能好&#xff09;实现。 负载均衡分为服务端负载均衡和客户端负载均衡。 服务端负载均衡 主要应用在 系统外部请求 和 网…

【网络取证箱】网络取证在线分析工具箱

【网络取证箱】网络取证在线分析工具箱 在线网站查询工具箱&#xff0c;没什么介绍的&#xff0c;所见即所得&#xff0c;在本文档里补充了其它一些网络安全资源&#xff0c;请忽用于非法活动&#xff0c;仅供学习研究—【蘇小沐】 &#xff08;一&#xff09;Whois查询 主要…

docker 进入容器内部命令

docker容器运行了&#xff0c;怎么进入容器内部查看内部的文件情况呢&#xff1f; 答&#xff1a;可以通过docker exec 的命令查看。 docker exec --help 可以查看命令介绍 &#xff1a; docker exec -it XXX /bin/bash XX为容器ID 进入容器内部 /bin/bash是需要添加的 不…

Java NIO和IO之间的区别

前言 NIO&#xff08;New IO&#xff09;&#xff0c;这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的&#xff0c;但实现方式不同&#xff0c;NIO主要用到的是块&#xff0c;所以NIO的效率要比IO高很多。在Java API中提供了两套NIO&#xff0c;一套是针对标准输入输出…

Python笔记|列表

Python 支持多种复合数据类型&#xff0c;可将不同值组合在一起。最常用的是列表——用方括号标注&#xff0c;逗号分隔的一组值。列表可以包含不同类型的元素&#xff0c;一般情况下&#xff0c;各个元素的类型相同&#xff1a; >>> squares [1, 4, 9, 16, 25] &g…