Golang教程一(环境搭建,变量,数据类型,数组切片map)

目录

一、环境搭建

1.windows安装

2.linux安装 

3.开发工具

二、变量定义与输入输出

1.变量定义

2.全局变量与局部变量

3.定义多个变量

4.常量定义

5.命名规范

6.输出

格式化输出

7.输入 

三、基本数据类型

1.整数型

2.浮点型

3.字符型

4.字符串类型

转义字符

多行字符串

5.布尔类型

四、数组、切片、map

1.数组

 2.切片

make函数

切片面试题 

3.Map

map面试题


一、环境搭建

官网

https://go.dev/dl/

访问不了的就访问中文网就好了

go安装包下载

https://studygolang.com/dl

安装指定版本的安装包就好了

1.windows安装

选择 xxx.windows-amd64.msi

  • 将go的对应bin目录设置为环境变量,这一步是方便可以在命令行里面直接使用go命令
  • 将go的第三方bin目录设置为环境变量,一般是在用户目录下,这一步是为了以后使用go install安装的第三方可执行文件可以直接使用

2.linux安装 

选择 xxx.linux-amd64.tar.gz

该站点比较快:All releases - The Go Programming Language

# 下载

wget https://golang.google.cn/dl/go1.22.2.linux-amd64.tar.gz

# 解压

tar -xvf go1.22.2.linux-arm64.tar.gz -C /usr/local

# 配置环境变量

echo 'export GO111MODULE=on' >> /etc/profile
echo 'export GOROOT=/usr/local/go' >> /etc/profile
echo 'export GOPATH=/home/gopath' >> /etc/profile
echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> /etc/profile

source /etc/profile

# 创建go包安装目录

mkdir -p /home/gopath

# 设置代理

go env -w GOPROXY=https://goproxy.cn,direct

# 检查成功

go version

3.开发工具

推荐goland

二、变量定义与输入输出

1.变量定义

package mainimport "fmt"func main() {// 先定义,再赋值var name stringname = "os_lee1"fmt.Println(name)// 定义加赋值var userName string = "os_lee1"fmt.Println(userName)
}

如果一个变量定义了,但是没有赋值,那么这个变量的值就是这个类型的 "零值" 

// 变量类型省略
var name = "os_lee"// 简单声明
name := "os_lee"

2.全局变量与局部变量

定义在函数体(包括main函数)内的变量都是局部变量,定义了就必须使用
定义在外部的变量就是全局变量,可以只定义不使用 

package mainimport "fmt"// 全局变量可以不使用
var userName = "oslee_全局" func main() {// 局部变量var name = "oslee_局部"// 在函数体内定义的变量,必须要使用fmt.Println(name)
}

3.定义多个变量

package mainimport "fmt"func main() {var name1, name2, name3 string // 定义多个变量var a1, a2 = "os", "lee" // 定义多个变量并赋值a3, a4 := "os", "lee" // 简短定义多个变量并赋值fmt.Printf("name1: %s, name2: %s, name3: %s\n", name1, name2, name3)fmt.Printf("a1: %s, a2: %s, a3: %s, a4: %s\n", a1, a2, a3, a4)
}
package mainimport "fmt"var (name     string = "os"userName        = "os_lee"
)func main() {fmt.Println(name, userName)
}

4.常量定义

定义的时候就要赋值
赋值之后就不能再修改了

package mainimport "fmt"const name string = "os_lee" // 定义就要赋值func main() {fmt.Println(name)
}

5.命名规范

核心思想:首字母大写的变量、函数。方法,属性可在包外进行访问

6.输出

package mainimport "fmt"func main() {fmt.Println("os_lee")fmt.Println(1)fmt.Println(true)fmt.Println("什么", "都", "可以", "输出")
}

格式化输出

%v按值的本来值输出
%+v在 %v 基础上,对结构体字段名和值进行展开
%#v输出 Go 语言语法格式的值
%T输出 Go 语言语法格式的类型和值
%%输出 % 本体
%b(oOdxX)整型的不同进制方式显示
%UUnicode 字符
%s字符串
%d整数
%f浮点数
%p指针,十六进制方式显示
package mainimport "fmt"func main() {fmt.Printf("%v\n", "你好")           // 可以作为任何值的占位符输出fmt.Printf("%v %T\n", "os", "lee") // 打印类型fmt.Printf("%d\n", 3)              // 整数fmt.Printf("%.2f\n", 1.25)         // 小数fmt.Printf("%s\n", "哈哈哈")          // 字符串fmt.Printf("%#v\n", "")            // 用go的语法格式输出,很适合打印空字符串// 还有一个用的比较多的就是将格式化之后的内容赋值给一个变量name := fmt.Sprintf("%v", "你好")fmt.Println(name)
}

7.输入 

package mainimport "fmt"func main() {fmt.Println("输入您的名字:")var name stringfmt.Scan(&name) // 这里记住,要在变量的前面加个&, 后面讲指针会提到fmt.Println("你输入的名字是", name)
}

三、基本数据类型

go语言的基本数据类型有

  1. 整数形
  2. 浮点型
  3. 复数
  4. 布尔
  5. 字符串

1.整数型

go语言的整数类型,具体细分有很多

var n1 uint8 = 2 
var n2 uint16 = 2 
var n3 uint32 = 2 
var n4 uint64 = 2 
var n5 uint = 2 
var n6 int8 = 2 
var n7 int16 = 2 
var n8 int32 = 2 
var n9 int64 = 2 
var n10 int = 2 

大家只需要记住以下几点

  1. 默认的数字定义类型是int类型
  2. 带个u就是无符号,只能存正整数
  3. 后面的数字就是2进制的位数
  4. uint8还有一个别名 byte, 一个字节=8个bit位
  5. int类型的大小取决于所使用的平台

例如uint8,那就是8个二进制位,都用来存储数据,那最小就是0,最大就是2的八次方-1=255

那int8,因为要拿一位存符合,使用实际只有七位可用,所以最小的就是负2的七次方=-128,最大的就是2的七次方-1=127

至于为什么要减一,其实很好理解,因为实际到最后一个数字的时候,已经向前进位了,例如一个小时是60分钟,但是分钟最大只有59

第五点的测试

我是64位操作系统,那么我会试一下int是不是就是int64的最大上限

2的63次方-1=9223372036854775807fmt.Printf("%.0f\n", math.Pow(2, 63))
var n1 int = 9223372036854775807
fmt.Println(n1)
var n2 int = 9223372036854775808 // 看它报不报错
fmt.Println(n2)

2.浮点型

Go语言支持两种浮点型数:float32 和 float64

  • float32 的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32
  • float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

如果没有显式声明,则默认是float64

3.字符型

注意哦,是字符,不是字符串

比较重要的两个类型是byte(单字节字符)和rune(多字节字符)

package mainimport "fmt"func main() {var c1 = 'a'var c2 = 97fmt.Println(c1) // 直接打印都是数字fmt.Println(c2)fmt.Printf("%c %c\n", c1, c2) // 以字符的格式打印var r1 rune = '中'fmt.Printf("%c\n", r1)
}

在 Go 中,字符的本质是一个整数,直接输出时,是该字符对应的 UTF-8 编码的码值
可以直接给某个变量赋一个数字,然后按格式化输出时 %c ,会输出该数字对应的 unicode 字符
字符类型是可以进行运算的,相当于一个整数,因为它都对应有 Unicode 码。

4.字符串类型

和字符不一样的是,字符的赋值是单引号,字符串的赋值是双引号 

var s string = "lee李"
fmt.Println(s)

转义字符

一些常用的转义字符

fmt.Println("os\tlee")             // 制表符
fmt.Println("os\nlee")             // 回车
fmt.Println("\"os\"lee")           // 双引号
fmt.Println("os\rlee")             // 回到行首
fmt.Println("C:\\pprof\\main.exe") // 反斜杠

其他的转义字符

"双引号
\反斜线
\a报警声
\b退格
\f换页
\n换行
\r回车替换
\v垂直制表符
\t制表符

多行字符串

在``这个里面,再出现转义字符就会原样输出了

package mainimport "fmt"func main() {str := `今天
天气
真好
`fmt.Println(str)
}

5.布尔类型

  • 布尔型数据只有 true(真)和 false(假)两个值
  • 布尔类型变量的默认值为false
  • Go 语言中不允许将整型强制转换为布尔型
  • 布尔型无法参与数值运算,也无法与其他类型进行转换
  • 零值问题
    如果我们给一个基本数据类型只声明不赋值,那么这个变量的值就是对应类型的零值,例如int就是0,bool就是false,字符串就是""

package mainimport "fmt"func main() {var a1 intvar a2 float32var a3 stringvar a4 boolfmt.Printf("%#v\n", a1)fmt.Printf("%#v\n", a2)fmt.Printf("%#v\n", a3)fmt.Printf("%#v\n", a4)
}

四、数组、切片、map

1.数组

数组(Array)是一种非常常见的数据类型,几乎所有的计算机编程语言中都会用到它

  1. 数组里的元素必须全部为同一类型,要嘛全部是字符串,要嘛全部是整数
  2. 声明数组时,必须指定其长度或者大小
package mainimport "fmt"func main() {var array [3]int = [3]int{1, 2, 3}fmt.Println(array)var array1 = [3]int{1, 2, 3}fmt.Println(array1)var array2 = [...]int{1, 2, 3}fmt.Println(array2)
}

 如果要修改某个值,只能根据索引去找然后替换

var array1 = [3]int{1, 2, 3}
array1[0] = 10 // 根据索引找到对应的元素位置,然后替换
fmt.Println(array1)

 2.切片

很明显啊,go里面的数组,长度被限制死了,所以不经常用

所以go出了一个数组plus,叫做slice(切片)

切片(Slice)相较于数组更灵活,因为在声明切片后其长度是可变的

package mainimport "fmt"func main() {// 定义一个字符串切片var list []stringlist = append(list, "枫枫")list = append(list, "知道")fmt.Println(list)fmt.Println(len(list)) // 切片长度// 修改第二个元素list[1] = "不知道"fmt.Println(list)
}

make函数

除了基本数据类型,其他数据类型如果只定义不赋值,那么实际的值就是nil

// 定义一个字符串切片
var list []string
fmt.Println(list == nil) // true

那么我们可以通过make函数创建指定长度,指定容量的切片了

make([]type, length, capacity)
package mainimport "fmt"func main() {// 定义一个字符串切片var list = make([]string, 0)fmt.Println(list, len(list), cap(list))fmt.Println(list == nil) // falselist1 := make([]int, 2, 2)fmt.Println(list1, len(list1), cap(list1))
}

为什么叫切片?
因为切片是数组切出来的

package mainimport "fmt"func main() {var list = [...]string{"a", "b", "c"}slices := list[:] // 左一刀,右一刀 变成了切片fmt.Println(slices)fmt.Println(list[1:2]) // b
}

切片排序

package mainimport ("fmt""sort"
)func main() {var list = []int{4, 5, 3, 2, 7}fmt.Println("排序前:", list)sort.Ints(list)fmt.Println("升序:", list)sort.Sort(sort.Reverse(sort.IntSlice(list)))fmt.Println("降序:", list)
}

切片面试题 

面试题1:什么是Go语言中的切片?

答案: Go语言中的切片(slices)是一种灵活的、动态大小的、基于数组的抽象数据类型。它并不存储任何数据,而是指向底层数组的一个片段,包含了三个信息:指向数组的指针、长度(len)和容量(cap)。长度表示切片当前拥有的元素个数,容量则是切片可以扩展到的最大元素个数,容量等于或大于长度。

面试题2:切片的扩容是如何工作的?

答案: 当向切片添加元素超出其当前容量时,Go语言会自动扩容切片。扩容的具体策略并不是固定的,但大致遵循以下规则:

  • 如果切片的容量不足以容纳新增元素,Go 会创建一个新的更大的底层数组,将原有数据复制到新数组,并更新切片的指针和容量。
  • 扩容因子通常为原来容量的2倍,但是也可能会根据实际情况调整,比如在Go 1.17版本之后,根据内存分配器的行为,扩容可能会跳跃式增长以更好地适应内存分配器的粒度。
  • 新容量至少会增加到原来的两倍+所需添加的元素数量,以尽量减少频繁的扩容操作。

面试题3:切片与数组有什么区别?

答案

  1. 长度可变性

    • 数组(array)的长度在声明时确定并且不能改变。
    • 切片(slice)虽然在声明时可以指定初始长度,但可以在运行时动态改变其长度(增删元素),不过容量有限制。
  2. 存储结构

    • 数组是一个定长的、连续的内存区域。
    • 切片不是数据结构,它只是一个描述符,指向一个数组的一部分。
  3. 引用行为

    • 数组变量直接存储数据,赋值操作会复制整个数组的内容。
    • 切片变量存储的是指向数组的指针和长度、容量信息,赋值操作只会复制切片描述符,不会复制底层数据。

面试题4:浅拷贝和深拷贝

浅拷贝(Shallow Copy): 浅拷贝是创建一个新的切片,但它仍然指向同一个底层数组。这意味着对新切片所做的修改会影响到原始切片所指向的数据。

// 示例1:直接赋值
original := []int{1, 2, 3}
copied := original // 此时copied是对original的浅拷贝

// 示例2:使用内置的copy函数
original := []int{1, 2, 3}
copied := make([]int, len(original))
copy(copied, original) // 这也是浅拷贝,copied和original共享相同的底层数组

深拷贝(Deep Copy): 深拷贝是创建一个与原始切片完全独立的新切片,包含一个全新的底层数组。对新切片所做的修改不会影响到原始切片。

// 手动循环遍历复制每一个元素
original := []int{1, 2, 3}
copied := make([]int, len(original))
for i, v := range original {
copied[i] = v
}// 或者使用反射(reflect)包,但请注意这不是最优实践,仅作演示
import "reflect"
original := []int{1, 2, 3}
copied := reflect.ValueOf(original).Clone().Interface().([]int)

3.Map

  1. Go语言中的map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合
  2. map的key必须是基本数据类型,value可以是任意类型
  3. 注意,map使用之前一定要初始化
package mainimport "fmt"func main() {// 声明var m1 map[string]string// 初始化1m1 = make(map[string]string)// 初始化2m1 = map[string]string{}// 设置值m1["name"] = "枫枫"fmt.Println(m1)// 取值fmt.Println(m1["name"])// 删除值delete(m1, "name")fmt.Println(m1)// 声明并赋值var m2 = map[string]string{}fmt.Println(m2)var m3 = make(map[string]string)fmt.Println(m3)}

map取值

  1. 如果只有一个参数接,那这个参数就是值,如果没有,这个值就是类型的零值
  2. 如果两个参数接,那第二个参数就是布尔值,表示是否有这个元素
package mainimport "fmt"func main() {// 声明并赋值var m1 = map[string]int{"age": 21,}age1 := m1["age1"] // 取一个不存在的fmt.Println(age1)age2, ok := m1["age1"]fmt.Println(age2, ok)
}

map面试题 

面试题1:什么是Go语言中的map?

答案: Go语言中的map是一种关联数组或字典类型的数据结构,它存储键值对(key-value pairs),通过键(key)快速查找对应的值(value)。键和值可以是任何类型,但键的类型必须支持相等比较,通常为整型、浮点型、字符串或复合类型(如结构体,但结构体内的字段必须支持相等比较)。

面试题2:Go语言中的map何时会引发panic?

答案

  • 在使用尚未初始化的map时(即nil map)执行读写操作,会导致panic。
  • 在迭代map的过程中,如果同时修改该map,也会导致panic,除非使用for range循环迭代并在循环体内使用delete函数删除元素。

面试题3:Go语言中map的扩容是如何进行的?

Go语言中的map在底层实现上使用了哈希表。当map中的元素数量越来越多,达到一定的负载因子时,Go语言会自动触发map的扩容操作。扩容是为了保持map操作的高效性,防止哈希冲突过于密集,导致性能下降。

扩容的具体流程如下:

  1. 负载因子判断: 当map的元素数量(entry count)与其桶(bucket)数量的比例超过一定阈值时(通常大约是6.5),map会触发扩容。这个阈值可以通过runtime包的内部常量mapExpandHeapSizemapExpandLoadFactor间接推算出来。

  2. 新桶分配: 扩容时,Go会创建一个新的、大小翻倍的哈希表。例如,如果原map的桶数量是2^N,则新表的桶数量将是2^(N+1)。

  3. 元素迁移: Go采用了渐进式(incremental)的迁移策略,不会一次性将所有元素从旧表迁移到新表。在每次map的读写操作时,如果发现正在进行扩容操作,就会顺带将旧表中的部分元素迁移到新表中。每次操作最多迁移两个桶(bucket)的数据。

  4. 保持引用关系: 在扩容过程中,map的旧表和新表会同时存在,直到所有元素都迁移到新表为止。旧表的最后一个桶会存储一个指向新表的指针,以确保在扩容过程中依然能正确找到已迁移的元素。

  5. 空间回收: 所有元素都迁移到新表后,旧表的空间最终会被垃圾回收机制释放。

值得注意的是,上述细节基于Go语言的早期版本,Go语言的map扩容机制在不同版本间可能会有所调整。最新的Go版本可能会根据具体情况采用不同的扩容策略和负载因子阈值。

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

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

相关文章

计算机网络(四)网络层

网络层 基本概念 网络互联: 将两个以上的计算机网络,通过一定的办法,用一种或多种通信处理设备(即中间设备)相互连接起来,以构成更大的网络系统。中间设备又称中间系统或中继系统 中继系统分为4种: 物理层中继系统…

Navicat的安装与破解

个人介绍 hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的…

EI级 | Matlab实现TCN-LSTM-MATT、TCN-LSTM、TCN、LSTM多变量时间序列预测对比

EI级 | Matlab实现TCN-LSTM-MATT、TCN-LSTM、TCN、LSTM多变量时间序列预测对比 目录 EI级 | Matlab实现TCN-LSTM-MATT、TCN-LSTM、TCN、LSTM多变量时间序列预测对比预测效果基本介绍程序设计参考资料 预测效果 基本介绍 【EI级】Matlab实现TCN-LSTM-MATT、TCN-LSTM、TCN、LSTM…

Unity 扩展自定义编辑器窗口

在Assets文件夹路径下任意位置创建Editor文件夹,将扩展编辑器的代码放在Editor文件夹下 生成编辑器窗口 代码中首先引用命名空间 using UnityEditor; 然后将创建的类继承自EditorWindow public class MenuEditor : EditorWindow 然后通过扩展编辑器菜单功能调用…

AI - 提示词意外收获 (5)

提示词: A soft pink rose with opalescent leaves, located in a surreal desert under the light of a binary star system, The dual shadows and contrasting lights create a dreamlike quality, emphasizing the roses unique beauty,翻译: 一种柔软的粉红…

动态规划|343.整数拆分

力扣题目链接 class Solution { public:int integerBreak(int n) {vector<int> dp(n 1);dp[2] 1;for (int i 3; i < n ; i) {for (int j 1; j < i / 2; j) {dp[i] max(dp[i], max((i - j) * j, dp[i - j] * j));}}return dp[n];} }; 思路 看到这道题目&…

153. 寻找旋转排序数组中的最小值

Problem: 153. 寻找旋转排序数组中的最小值 文章目录 思路解题方法复杂度Code 思路 排序( O ( n l o g n ) O(nlogn) O(nlogn)) 或者 循环一次( O ( n ) O(n) O(n))&#xff0c;但时间复杂度均不满足要求 解题方法 二分 当数组旋转后&#xff0c;只有可能出现如图的两种情况&am…

数据库查询:查询入参类型和数据库字段类型不匹配导致的问题

问题&#xff1a;假设我们现在有这样的一张表 CREATE TABLE test_person (id int(20) NOT NULL COMMENT 主键,name varchar(20) DEFAULT NULL COMMENT 姓名,gender char(2) DEFAULT NULL COMMENT 性别,birthday date DEFAULT NULL COMMENT 生日,created_time timestamp NULL D…

ubuntu 23.10.1 mysql 安装

注&#xff1a;请进入root用户模式下操作&#xff0c;若没有&#xff0c;输入命令前加上sudo 1、更新软件包列表 apt update2、安装最新版的Mysql服务器 apt install mysql-server -y如果不加-y 会在安装过程中&#xff0c;系统将提示你设置MySQL的root密码。确保密码足够强…

《云原生安全攻防》-- 云原生攻防矩阵

在本节课程中&#xff0c;我们将开始学习如何从攻击者的角度思考&#xff0c;一起探讨常见的容器和K8s攻击手法&#xff0c;包含以下两个主要内容&#xff1a; 云原生环境的攻击路径: 了解云原生环境的整体攻击流程。 云原生攻防矩阵: 云原生环境攻击路径的全景视图&#xff0…

Unity解决:导出安卓apk 安装时报错:应用未安装:软件包似乎无效

Unity2018.4.36 导出安卓apk 安装时报错&#xff1a;应用未安装&#xff1a;软件包似乎无效 解决办法&#xff1a;因为安装到安卓12 需要添加添加过滤规则 在AS工程AndroidManifest.xml 添加过滤规则即可。 android:exported"true"

记录flume运行时报NullPointerException异常

【背景说明】 我要起一个将kafka上的topic_log主题中的数据上传到hdfs上的flume进程。 这是我的flume配置文件脚本&#xff1a; #定义组件 a1.sourcesr1 a1.channelsc1 a1.sinksk1#配置source1 a1.sources.r1.type org.apache.flume.source.kafka.KafkaSource a1.sources.r…

使用 npm 工具高效更新项目依赖包

团队内部会用工具定时检查包的最新版本并通知&#xff0c;以便我们及时跟进社区进展&#xff0c;避免和技术栈出现版本脱节导致无法使用最新特性和优化内容 这里只说明手动查看和更新包的主要几个命令。 npm outdated&#xff1a;检查项目中过时的依赖包及其最新版本。 npm i…

MVSplat:稀疏多视点图像的高效3D高斯溅射

MVSplat: Efficient 3D Gaussian Splatting from Sparse Multi-View Images MVSplat&#xff1a;稀疏多视点图像的高效3D高斯溅射 Yuedong Chen1  Haofei Xu2,3  Chuanxia Zheng4  Bohan Zhuang 粤东陈浩飞徐 2,3 郑传霞 4 庄伯涵1 Marc Pollefeys2,5  Andreas Geiger3  T…

如何应对孩子情绪化地发脾气?

你有小孩儿吗&#xff1f;是否受孩子发脾气的困扰&#xff1f;如果都没有&#xff0c;可以跳出去看看别人的文章了&#xff0c;如果有&#xff0c;可以继续往下看。 白牙有个小闺女&#xff0c;3 岁半&#xff0c;今天她看大人洗脚&#xff0c;她也想洗&#xff0c;但没来得及给…

[lesson31]完善的复数类

完善的复数类 完善的复数类 复数类应该具有的操作 运算&#xff1a;&#xff0c;-&#xff0c;*&#xff0c;/比较&#xff1a;&#xff0c;!赋值&#xff1a;求模&#xff1a;modulus 利用操作符重载 统一复数与实数的运算方式统一复数与实数的比较方式 注意事项 C规定赋…

HarmonyOS开发实例:【事件的订阅和发布】

介绍 本示例主要展示了公共事件相关的功能&#xff0c;实现了一个检测用户部分行为的应用。具体而言实现了如下几点功能&#xff1a; 1.通过订阅系统公共事件&#xff0c;实现对用户操作行为&#xff08;亮灭屏、锁屏和解锁屏幕、断联网&#xff09;的监测&#xff1b; 2.通…

气象观测站点数据下载与处理

一、下载途径 全国400多个气象站气候数据&#xff08;1942-2022&#xff09; 王晓磊&#xff1a;中国空气质量/气象历史数据 | 北京市空气质量历史数据 气象数据免费下载网站整理 中国气象站观测的气象数据怎么下载 二、R语言处理 2.1 提取站点文件 library(dplyr) library(…

探索顶级短视频素材库:多样化选择助力创作

在数字创作的浪潮中&#xff0c;寻找优质的短视频素材库是每位视频制作者的必经之路。多种短视频素材库有哪些&#xff1f;这里为您介绍一系列精选的素材库&#xff0c;它们不仅丰富多样&#xff0c;而且高质量&#xff0c;能极大地提升您的视频创作效率和质量。 1.蛙学网 蛙学…

绝地求生:PWS韩国联赛结束:KDF夺冠,DNW三年来首次错失世界赛

4.14号PWS韩国联赛结束了为期3天的决赛&#xff0c;KDF战队以73击杀117分获PWS第一阶段冠军&#xff0c;队内Heaven获MVP&#xff0c;DK_seoul伤害王。 常规赛靠前的DNW和Gen.G决赛均发挥失常都没有进入前八&#xff0c;其中上届世界冠军DNW在双S核心出走后时隔三年首次错失世界…