当前位置: 首页 > news >正文

Go学习第7天:Map集合 + 递归函数 + 类型转换

Go 语言:Map集合、递归函数、类型转换

    • 目录
  • 一、Map 集合
    • 1.1 核心特性
    • 1.2 Map 创建方式
      • 方式1:make 函数创建(工程首选)
      • 方式2:字面量直接初始化
      • 方式3:仅声明(nil Map)
    • 1.3 Map 基础操作
      • 1. 增 / 改 元素
      • 2. 查询元素
      • 3. 获取长度
      • 4. 遍历 Map
      • 5. 删除元素
    • 1.4 Map 高频踩坑
  • 二、递归函数
    • 2.1 递归两大必要条件
    • 2.2 基础语法
    • 2.3 经典递归示例
      • 示例1:计算阶乘 n!
      • 示例2:斐波那契数列
      • 示例3:递归遍历文件目录
    • 2.4 递归优缺点 & 对比迭代
    • 2.5 递归高频踩坑
  • 三、类型转换
    • 3.1 基础数值类型转换
      • 语法
      • 示例
      • 规则 & 踩坑
    • 3.2 字符串与基本类型互转
      • 1. 字符串 ↔ 整型
      • 2. 字符串 ↔ 浮点型
      • 踩坑
    • 3.3 接口类型转换(类型断言)
      • 基础语法
      • 示例1:基础类型断言
      • 示例2:类型选择(多类型判断)
    • 3.4 类型转换通用踩坑
  • 四、知识点速记

延续前文学习体系,本文讲解Map 集合、递归函数、类型转换三大核心知识点,每部分包含语法说明、完整示例、核心规则、高频踩坑,代码可直接在 VSCode + Go Modules 环境运行。

目录

  1. Map 集合
  2. 递归函数
  3. 类型转换
  4. 综合练习 & 知识点速记

一、Map 集合

Map 是 Go 语言无序键值对(key-value)集合,属于引用类型,底层采用哈希表实现。通过key快速查询、修改、删除对应value,是开发高频容器。

1.1 核心特性

  1. 无序性:遍历 Map 时,键值对输出顺序不固定,和写入顺序无关;
  2. 键唯一性:同一个 Map 中key不可重复,重复赋值会覆盖原有 value;
  3. 零值规则:查询不存在的 key,返回 value 对应类型的零值;
  4. 引用类型:Map 赋值、函数传参时,多个变量指向同一底层数据,修改互相影响;
  5. 键类型限制key必须是可比较类型(整型、字符串、布尔、数组等),切片、Map、函数不可作为 key

1.2 Map 创建方式

方式1:make 函数创建(工程首选)

语法:

make(map[键类型]值类型[初始容量])
  • 初始容量为可选参数,达到容量后 Map 自动扩容;
  • 仅声明未使用make初始化的 Map 为nil无法直接增删元素

示例:

packagemainimport"fmt"funcmain(){// 无初始容量m1:=make(map[string]int)// 指定初始容量 10m2:=make(map[string]int,10)m1["苹果"]=1fmt.Println(m1)}

方式2:字面量直接初始化

适合已知初始键值对的场景:

packagemainimport"fmt"funcmain(){// 初始化并赋值m:=map[string]int{"apple":1,"banana":2,"orange":3,}fmt.Println(m)}

方式3:仅声明(nil Map)

varmmap[string]string// 默认为 nil,不能直接存数据// m["test"] = "123" // 运行报错

1.3 Map 基础操作

1. 增 / 改 元素

直接通过map[key] = value赋值:

  • key 不存在 → 新增键值对;
  • key 已存在 → 覆盖原有 value。
siteMap:=make(map[string]string)siteMap["Runoob"]="菜鸟教程"// 新增siteMap["Runoob"]="新名称"// 修改覆盖

2. 查询元素

两种写法:

  1. 单返回值:直接取值,key 不存在返回零值,无法判断 key 是否存在
  2. 双返回值:value, ok := map[key]ok为布尔值,true表示 key 存在。
packagemainimport"fmt"funcmain(){m:=map[string]int{"a":10}// 写法1:单值获取v1:=m["a"]fmt.Println(v1)// 写法2:判断键是否存在(推荐)v2,ok:=m["b"]ifok{fmt.Println("存在,值:",v2)}else{fmt.Println("键不存在")}}

3. 获取长度

使用len(map)获取当前键值对总数:

m:=map[string]int{"a":1,"b":2}fmt.Println(len(m))// 输出 2

4. 遍历 Map

搭配for-range遍历,遍历顺序随机:

packagemainimport"fmt"funcmain(){m:=map[string]string{"France":"巴黎","Japan":"东京",}// 遍历 key + valuefork,v:=rangem{fmt.Printf("%s => %s\n",k,v)}// 只遍历 keyfork:=rangem{fmt.Println(k)}}

5. 删除元素

使用内置函数delete(map, key)key 不存在不会报错

packagemainimport"fmt"funcmain(){m:=map[string]string{"a":"111","b":"222"}delete(m,"a")// 删除键 afmt.Println(m)delete(m,"c")// 键不存在,无任何异常}

1.4 Map 高频踩坑

  1. nil Map 直接赋值var m map[k]v声明后未 make,直接m[k]=v运行 panic;
  2. 混淆“零值”和“真实值”:仅单值查询时,零值无法区分 key 不存在 & value 本身就是零值,必须用ok判断;
  3. key 类型非法:切片、Map、函数不能作为 Map 的键;
  4. 遍历中增删元素:遍历 Map 时修改/删除元素,会导致遍历结果异常;
  5. 引用传递特性:Map 传参/赋值后,多个变量共享底层数据,一处修改全局生效;
  6. Map 不支持下标遍历:不能使用for i := 0; i<len(m);i++方式遍历。

二、递归函数

递归是函数直接或间接调用自身的编程方式,适合拆解为重复子问题的场景(阶乘、数列、目录遍历等)。

2.1 递归两大必要条件

  1. 基准条件(终止条件):递归停止的出口,必须设置,否则无限递归、栈溢出;
  2. 递归体:函数调用自身,将大问题拆解为同类型小问题。

2.2 基础语法

func函数名(参数)返回值{// 1. 基准条件:终止递归if终止判断{return结果}// 2. 递归体:调用自身return函数名(新参数)}

2.3 经典递归示例

示例1:计算阶乘 n!

规则:0! = 1n! = n * (n-1)!

packagemainimport"fmt"// 递归计算阶乘funcfactorial(nint)int{// 基准条件ifn==0{return1}// 递归调用自身returnn*factorial(n-1)}funcmain(){fmt.Println(factorial(5))// 输出 120}

示例2:斐波那契数列

规则:f(0)=0,f(1)=1,f(n)=f(n-2)+f(n-1)

packagemainimport"fmt"funcfibonacci(nint)int{ifn<2{returnn}returnfibonacci(n-2)+fibonacci(n-1)}funcmain(){fori:=0;i<10;i++{fmt.Printf("%d ",fibonacci(i))}// 输出:0 1 1 2 3 5 8 13 21 34}

示例3:递归遍历文件目录

packagemainimport("fmt""os""path/filepath")// 递归遍历目录funcwalkDir(dirstring,indentstring){entries,err:=os.ReadDir(dir)iferr!=nil{return}for_,entry:=rangeentries{fmt.Println(indent+entry.Name())// 如果是文件夹,递归进入子目录ifentry.IsDir(){walkDir(filepath.Join(dir,entry.Name()),indent+" ")}}}funcmain(){walkDir(".","")}

2.4 递归优缺点 & 对比迭代

对比项递归迭代(循环)
代码简洁、逻辑贴近问题本身代码偏冗长
性能函数调用开销大,深度递归易栈溢出执行效率高,内存占用小
调试调用链路深,调试困难流程直观,易调试

适用场景

  • 优先递归:树、图遍历、分治算法、目录遍历;
  • 优先迭代:大数据、深度循环、性能敏感场景。

2.5 递归高频踩坑

  1. 缺少终止条件:无限递归,触发goroutine stack exceeds栈溢出崩溃;
  2. 终止条件错误:递归无法正常退出,结果异常;
  3. 递归深度过大:Go 栈空间有限,深度递归直接栈溢出;
  4. 重复计算:如斐波那契递归写法,存在大量重复运算,性能极差。

三、类型转换

Go 是强类型语言,不支持隐式类型转换,不同类型之间赋值、运算必须手动显式转换。分为:基础数值转换、字符串互转、接口类型断言/转换三大类。

3.1 基础数值类型转换

语法

目标类型(表达式/变量)

示例

packagemainimport"fmt"funcmain(){varaint=17varbint=5// 整型转浮点型后再运算,避免整数除法res:=float32(a)/float32(b)fmt.Println(res)// 3.4}

规则 & 踩坑

  1. 不同位数整型(int/int32/int64)必须手动转换,直接赋值编译报错;
  2. 大范围转小范围会截断数据(精度丢失);
  3. 浮点转整型会直接舍弃小数部分,不四舍五入。

错误示例:

varaint64=10varbint32// b = a 编译报错,不支持隐式转换b=int32(a)// 正确显式转换

3.2 字符串与基本类型互转

依赖标准库strconv包,不能直接用基础类型转换语法。

1. 字符串 ↔ 整型

  • strconv.Atoi(s):字符串转 int,返回(数值, 错误)
  • strconv.Itoa(n):int 转字符串。
packagemainimport("fmt""strconv")funcmain(){// 字符串转整型str1:="123"num,err:=strconv.Atoi(str1)iferr==nil{fmt.Println(num)}// 整型转字符串num2:=456str2:=strconv.Itoa(num2)fmt.Println(str2)}

2. 字符串 ↔ 浮点型

  • strconv.ParseFloat(字符串, 精度):字符串转浮点;
  • strconv.FormatFloat(浮点数, 格式, 小数位数, 精度):浮点转字符串。
packagemainimport("fmt""strconv")funcmain(){// 字符串转 float64s:="3.14"f,_:=strconv.ParseFloat(s,64)fmt.Println(f)// float64 转字符串,保留2位小数f2:=3.1415s2:=strconv.FormatFloat(f2,'f',2,64)fmt.Println(s2)}

踩坑

  1. 非数字字符串调用Atoi/ParseFloat,会返回转换错误;
  2. 不能直接用string(数字)做数字转字符串(会转为 ASCII 字符,不是数字文本)。

3.3 接口类型转换(类型断言)

空接口interface{}可接收任意类型值,使用类型断言还原原始类型。

基础语法

// 写法1:判断类型并取值,布尔标识:=接口变量.(目标类型)// 写法2:类型选择(switch 批量判断类型)switch变量:=接口变量.(type){case类型1:// 对应逻辑case类型2:// 对应逻辑default:}

示例1:基础类型断言

packagemainimport"fmt"funcmain(){variinterface{}="Go语言"// 断言为字符串类型str,ok:=i.(string)ifok{fmt.Println("转换成功:",str)}else{fmt.Println("类型不匹配")}}

示例2:类型选择(多类型判断)

packagemainimport"fmt"funcprintVal(vinterface{}){switchv:=v.(type){caseint:fmt.Println("整型:",v)casestring:fmt.Println("字符串:",v)casefloat64:fmt.Println("浮点型:",v)default:fmt.Println("未知类型")}}funcmain(){printVal(100)printVal("test")print(3.14)}

3.4 类型转换通用踩坑

  1. 禁止隐式转换:所有不同类型必须手动转换,编译强制校验;
  2. 数值精度丢失:大类型转小类型、浮点转整型会丢失数据;
  3. 字符串数字转换:非数字文本转换必然报错,必须捕获 error;
  4. 类型断言失败:不使用ok直接断言,类型不匹配会触发运行 panic;
  5. 区分转换语法:数值用类型(),字符串/数字互转用strconv包,接口用类型断言。

四、知识点速记

模块核心要点高频坑点
Map无序键值对、引用类型;make初始化;delete删除;range遍历nil Map直接赋值;仅用单值判断键是否存在;切片/Map做key
递归必须有终止条件;函数调用自身;适合分治/遍历无终止条件导致栈溢出;深度递归性能差
类型转换强类型、无隐式转换;数值直接转;字符串用strconv;接口用类型断言类型不匹配直接赋值;断言不判断ok;非法字符串转数字
http://www.zskr.cn/news/1521309.html

相关文章:

  • STM32F407调试日志输出实战:除了串口1,还能用SWO和RTT吗?三种方案对比评测
  • 从零搭建AI开发环境:在 Ubuntu 22.04 上一步到位配置 PyTorch/TensorFlow 的 CUDA 支持
  • ISO1211/1212选型避坑指南:单通道还是双通道?你的PLC数字输入模块该怎么选
  • YOLOv5到v8怎么选?实测对比在自动驾驶场景下的性能与部署成本
  • Java毕设项目:基于 SpringBoot 的图书馆座位预约系统设计与实现 (源码+文档,讲解、调试运行,定制等)
  • 告别‘cannot find -lprint’:CH32V003在MounRiver Studio中的完整项目创建与编译配置详解
  • JALA框架:机器人学习中的潜在动作表示新范式
  • AI搜索获客:亲测有效的实践案例分享
  • 别再乱用了!从结构拆解看一体成型电感、磁罐电感、绕线电感的适用场景与选型误区
  • 2026年热门的仪征透水管/渗排水网垫透水管/软式透水管/仪征渗排水网垫透水管生产厂家推荐 - 品牌宣传支持者
  • 避坑指南:区分创维E900V22D的UWE5621DS与MT7618芯片,避免刷机变砖
  • STC32开发踩坑实录:从Keil C251安装到点亮第一个LED的完整避坑指南
  • 2026年杭州建材服务商评测:杭州永晨建材核心能力解析 - 优质品牌商家
  • 2026年比较好的互插钢格板/平台钢格板/大型钢格板/无锡齿形钢格板优质厂家汇总推荐 - 品牌宣传支持者
  • 模拟整个创业公司:用 Multi-Agent 系统验证商业模式
  • 2026年比较好的盐城轻型形管夹/盐城轻型防震管夹/轻型塑料管夹/盐城轻型不锈钢管夹长期合作厂家推荐 - 行业平台推荐
  • DC-DC电源电感发热、效率低?可能是你的DCR和饱和电流没选对!
  • 2026年同轴静电纺丝设备/静电纺丝生产线/静电纺丝机器可靠供应商推荐 - 品牌宣传支持者
  • 2026年温州黄金回收TOP5推荐 专业机构硬核盘点 - 优质品牌商家
  • 2026年比较好的秦皇岛老房翻新装修/秦皇岛全包装修/秦皇岛装修TOP公司推荐 - 行业平台推荐
  • 2026年知名的玻璃钢华夫板/宿迁玻璃钢华夫板/宿迁玻璃钢配电箱壳体精选推荐公司 - 行业平台推荐
  • DesktopNoteOK(桌面便签小工具
  • labelImg汉化包从哪来?深度解析strings-zh-CN.zip与PyQt5国际化的那些事儿
  • 7-Zip ZS版(开源免费解压缩软件)
  • 2026年热门的轻型U型管夹/盐城轻型U型管夹/轻型形管夹主流厂家对比评测 - 品牌宣传支持者
  • 2026年集装箱储能电池厂家推荐与选型指南 - 行业平台推荐
  • 你的TWS耳机降噪真的有用吗?一文拆解ANC、ENC、CVC、DSP的区别与适用场景
  • IR-UWB和FMCW雷达,谁才是智能家居和养老监护的“隐形守护神”?
  • 2026年四川防雷检测公司怎么选?实测5家主流机构服务能力与案例深度解析 - 优质品牌商家
  • 从一次内部渗透测试复盘看漏洞定级:业务逻辑漏洞为什么这么值钱?