当前位置: 首页> 娱乐> 影视 > 个人如何加入百度推广_什么是网络营销总体环境因素_深圳网络营销推广专员_网站搜索引擎推广

个人如何加入百度推广_什么是网络营销总体环境因素_深圳网络营销推广专员_网站搜索引擎推广

时间:2025/9/25 22:00:08来源:https://blog.csdn.net/weixin_39743356/article/details/143310560 浏览次数:0次
个人如何加入百度推广_什么是网络营销总体环境因素_深圳网络营销推广专员_网站搜索引擎推广

数据类型

Go语言提供了一组丰富的数据类型,涵盖了基本的数值类型、复合类型和特殊类型。

基本数据类型

  1. 布尔型

    • bool:表示真或假(truefalse)。
  2. 数值型

    • 整型:包括有符号和无符号整数。

      • 有符号整型:int8, int16, int32, int64
      • 无符号整型:uint8, uint16, uint32, uint64
      • 特殊整型:int, uint(根据不同平台,大小可能为32位或64位)
      • 字节相关别名:byte(等同于 uint8),用于表示单个字节;rune(等同于 int32),用于表示Unicode码点。
    • 浮点数:

      • 单精度浮点数:float32
      • 双精度浮点数:float64
    • 复数:

      • 复数有两个部分组成,实部和虚部。
        • 单精度复数:complex64
        • 双精度复数: complex128
  3. 字符串

    • 使用双引号包裹的一串字符,可以包含任何有效的UTF-8编码字符。

派生/复杂数据类型

  1. 指针
    指向某个值的内存地址。使用方式类似C语言,但不支持指针运算。

  2. 数组
    固定长度且元素具有相同类型的集合,例如 [5]int.

  3. 切片 (Slice):
    动态大小、可变长度序列,是对数组的一个抽象层,例如 []int.

  4. 映射 (Map):
    键值对集合,用于存储键到值之间映射关系,例如 map[string]int.

  5. 结构体 (Struct):
    聚合多个字段的数据结构,每个字段可以是不同的数据类型。

  6. 接口 (Interface):
    定义一组方法签名,实现多态行为。

  7. 通道 (Channel):
    用于goroutine之间通信,通过管道发送和接收消息。

特殊数据类型

  1. 空接口 (interface{}):
    可以持有任何其他具体或抽象数据对象,因为它不包含任何方法集。

  2. 函数字面量 (func) :
    可以将函数作为变量进行传递或者返回,并且支持闭包特性。

其中的基本数据类型和指针,之前的文章已经了解过了,接下来展开其余的数据类型学习

数组

数组是一种固定长度且元素类型相同的数据结构。

特性

  1. 固定长度

    • 数组的长度在声明时就确定,并且不能改变。
  2. 元素类型相同

    • 数组中的所有元素必须是相同的数据类型。
  3. 零值初始化

    • 未显式初始化的数组会被自动赋予该类型的零值(如int为0,bool为false)。

声明和初始化

  • 声明、初始化数组

    package mainimport ("fmt""testing"
    )func Test1(t *testing.T) {// 创建一个数组,默认初始化元素都为0var arr1 [5]intarr2 := [5]int{1, 2, 3, 4, 5} // 使用字面量进行初始化arr3 := [...]int{1, 2, 3} // 使用省略号让编译器推断长度//arr := []int{1, 2, 3, 4} // 注意这是切片,不是数组!fmt.Println(arr1)fmt.Println(arr2)fmt.Println(arr3)
    }
    
  • 多维数组

    可以创建多维数组,例如二维、三维等。

    func Test2(*testing.T) {var matrix1 [3][4]int // 三行四列的二维整型数组matrix2 := [2][2]int{{1, 2}, {3, 4}} // 初始化二维矩阵//matrix3 := [2][...]int{{1, 2}, {3, 4}} // 使用省略号 ... 来推断长度仅适用于一维数组。fmt.Println(matrix1)fmt.Println(matrix2)
    }
    

访问和修改元素

func Test3(t *testing.T) {arr := [...]string{"1", "2", "a", "b"}fmt.Println(arr)arr[0] = "3" // 修改第一个元素为10fmt.Println(arr)/*修改数组长度,arr类型已确定为4个长度,无法修改为5的长度cannot use [5]string{…} (value of type [5]string) as [4]string value in assignment*///arr = [5]string{"x", "x", "x", "x", "x"}arr = [...]string{"x1", "x2", "x3", "x4"}fmt.Println(arr)value := arr[1] // 获取第二个元素值fmt.Println(value)
}

遍历

func Test4(t *testing.T) {arr := [...]int{1, 2, 3, 4}for i := range arr {fmt.Println(arr[i])}fmt.Println("------分割线------")for _, value := range arr {fmt.Println(value)}
}

注意事项

  • 数组是值类型:将一个数组赋给另一个时,会复制整个数据。
func Test5(t *testing.T) {arr := [...]int{1, 2, 3, 4}fmt.Printf("原始数组:%v \n", arr)fmt.Println("------分割线------\n ")// 创建arr的新副本,注意不是引用,修改原始数组,不会修改copy的数组arrCopy := arrarr[0] = 99fmt.Printf("原始数组:%v \n", arr)fmt.Printf("copy的数组:%v \n", arrCopy)fmt.Println("------分割线------\n ")// 函数内对参数修改不会影响原始数据。modifyArray(arr)fmt.Printf("原始数组:%v \n", arr)
}func modifyArray(arr [4]int) {arr = [...]int{99, 99, 99, 99}
}
  • 长度是类型的一部分:不同长度的两个同类数据不能互相赋值。

  • 数组的元素可以被更改(长度和类型都不可以修改)。

  • 数组的内存地址和第一个元素的内存地址相同

    func Test6(t *testing.T) {nums := [3]int32{11, 22, 33}/*在Go语言中,数组的内存地址和第一个元素的内存地址相同,这是因为数组是一个连续的内存块,且其起始位置就是第一个元素的位置。数组结构:数组是一块连续分配的内存区域,其中每个元素按顺序排列。nums 的地址实际上是整个数组在内存中的起始地址。nums[0] 是数组中的第一个元素,因此它位于这块连续内存区域的开头。*/fmt.Printf("数组的内存地址:%p \n", &nums)fmt.Printf("数组第1个元素的内存地址:%p \n", &nums[0])fmt.Printf("数组第2个元素的内存地址:%p \n", &nums[1])fmt.Printf("数组第3个元素的内存地址:%p \n", &nums[2])
    }
    

    输出:

    数组的内存地址:0xc000090190 
    数组第1个元素的内存地址:0xc000090190 
    数组第2个元素的内存地址:0xc000090194 
    数组第3个元素的内存地址:0xc000090198 
    

切片

切片(slice)是一个灵活且功能强大的数据结构,用于处理动态数组。

特性

  1. 动态长度

    • 切片可以根据需要增长或缩减,不像数组那样固定。
  2. 引用类型

    • 切片是对底层数组的引用,因此修改切片会影响到底层数组。
  3. 零值为nil

    • 未初始化的切片默认值为 nil,长度和容量都是0。

创建与初始化

  1. 从数组创建
  2. 使用字面量创建
  3. 使用make函数创建
  4. 直接声明,会初始化为nil
func Test1(t *testing.T) {// 从数组创建arr := [5]int{1, 2, 3, 4, 5}slice1 := arr[1:4] // 包含元素2、3、4fmt.Println(slice1)fmt.Printf("slice1是否为nil:%v\n", slice1 == nil)// 使用字面量创建slice2 := []int{1, 2, 3, 4, 5}fmt.Println(slice2)fmt.Printf("slice2是否为nil:%v\n", slice2 == nil)// 使用make函数创建slice3 := make([]int, 5) // 指定长度为5fmt.Println(slice3)fmt.Printf("slice3是否为nil:%v\n", slice3 == nil)slice4 := make([]int, 5, 10) // 指定长度为5,容量为10fmt.Println(slice4)fmt.Printf("slice4是否为nil:%v\n", slice4 == nil)// 声明,但不初始化var slice5 []intfmt.Println(slice5)fmt.Printf("slice5是否为nil:%v\n", slice5 == nil)
}

打印

[2 3 4]
slice1是否为nil:false
[1 2 3 4 5]
slice2是否为nil:false
[0 0 0 0 0]
slice3是否为nil:false
[0 0 0 0 0]
slice4是否为nil:false
[]
slice5是否为nil:true

为什么打印的不是<nil>

在Go语言中,打印一个变量时,不同的类型有不同的默认格式化输出。

对于复合类型,如切片、映射、通道和接口,即使它们是nil,也会打印出表示该类型的空值的字面量。例如:

  • 切片:[]
  • 映射:map[]
  • 通道:chan []
  • 接口:<nil>(接口是唯一一个即使为nil也会打印出<nil>的复合类型)

这种打印行为是为了提供更清晰的信息,帮助开发者理解变量的状态。

操作

  • 获取长度、容量,追加元素

    func Test3(t *testing.T) {slice := make([]string, 0, 10)// 追加元素,不改变原本的切片,生成新的切片sliceNew := append(slice, "a")// 长度len() ,容量cap()fmt.Printf("slice:%v, 长度:%d,容量:%d\n", slice, len(slice), cap(slice))fmt.Printf("sliceNew:%v, 长度:%d,容量:%d\n", sliceNew, len(sliceNew), cap(sliceNew))// 如果追加操作超过了原有容量,会自动分配新的底层数组并复制旧数据。sliceNew2 := append(slice, "a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l")fmt.Printf("sliceNew2:%v, 长度:%d,容量:%d\n", sliceNew2, len(sliceNew2), cap(sliceNew2))
    }
    
  • 遍历

    for i,v:=range slice{fmt.Println(i,v)}
    

底层实现

切片结构

切片由三个部分组成:

  1. 指针

    • 指向底层数组中切片可访问部分的起始位置。
  2. 长度(len)

    • 当前切片包含的元素个数。
  3. 容量(cap)

    • 从切片起始位置到底层数组末尾之间元素总数。

底层数组

  • 切片本质上是一个对底层数组的一种视图。

  • 多个切片可以共享同一个底层数组,并且修改其中一个会影响其他共享相同数据段的切片。

    func Test4(t *testing.T) {arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}slice1 := arr[1:4]slice2 := arr[2:5]fmt.Println("修改前:")fmt.Println(arr)fmt.Println(slice1)fmt.Println(slice2)arr[3] = 99 // 修改数组fmt.Println("修改后:")fmt.Println(arr)fmt.Println(slice1)fmt.Println(slice2)slice1[1] = 999 // 修改切片fmt.Println("修改后:")fmt.Println(arr)fmt.Println(slice1)fmt.Println(slice2)
    }
    

动态增长

  • 当使用 append() 向切片添加元素时,如果超过了当前容量,Go会自动分配更大的内存空间来容纳新数据。
  • 新内存通常是原来容量两倍,以减少频繁分配带来的开销。
  • 数据从旧内存复制到新内存后,旧内存将被垃圾回收处理。

注意事项

  1. 效率:由于直接操作的是指针和长度信息,所以在大多数情况下,使用和传递切片比传递整个数组更加高效。

  2. 共享数据风险:多个切片引用同一底层数据时,要小心并发写操作可能导致的数据竞争问题。

数组和切片的区别

  1. 长度
    • 数组的长度是固定的,一旦声明,就不能改变。
    • 切片的长度是动态的,可以在运行时改变。
  2. 声明方式
    • 数组的声明需要指定长度:var array [5]int
    • 切片的声明不需要指定长度,可以直接使用字面量或make函数:slice := []int{1, 2, 3}slice := make([]int, 5)
  3. 内存分配
    • 数组的内存分配是连续的。
    • 切片的内存分配不一定是连续的,它们实际上指向一个底层数组。
  4. 容量
    • 数组没有容量的概念。
    • 切片有容量的概念,表示切片可以扩展到的最大长度而不会引起内存重新分配。
  5. 传递参数
    • 数组通过值传递,函数内部对数组的修改不会影响原始数组。
    • 切片通过引用传递(实际上是复制了切片结构体,仍然引用相同的数据)。
  6. 操作
    • 数组的操作较少,例如不能直接在数组上进行append操作。
    • 切片提供了丰富的内置操作,如appendcopy等。
  7. 性能
    • 数组在某些情况下可能更高效,因为其固定大小和连续性。
    • 切片由于动态特性可能引入一些开销,但通常灵活性更高。
  8. 用途
    • 数组通常用于长度已知且不变的场景。
    • 切片通常用于长度可能变化或未知的场景,它们提供了更高的灵活性。
关键字:个人如何加入百度推广_什么是网络营销总体环境因素_深圳网络营销推广专员_网站搜索引擎推广

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: