Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用
Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用
在 Flutter 里,Key 对象存在的目的主要是区分和维持 Widget 的状态,它是控件在渲染树里的「复用」标识之一,这一点在之前的《深入 Flutter 和 Compose 在 UI 渲染刷新时 Diff 实现对比》 聊到过,可以说 Key 的存在关乎了 Flutter 的性能,因为它的作用就是提高 Element Tree 的复用效率,例如减少匹配阶段所需的 Widget 比较次数。
另外通过 Key 还可以提高如 AnimatedList
、ListView
里重新排序时对应 Item widget 的效率,通过将 Key 分配给 Item ,Flutter 可以更有效地识别何时添加、删除或更新列表并执行动画,在这个时候, Key 可以确保每个 Item 即使在对列表进行排序时也保持其状态。
大多数情况下,无状态的 Widget 是不需要 Key,而默认情况下,我们在不主动配置 Key 的时候,它会是 null :
也就是在没有 Key 的情况下,framewok 一般只判断 runtimeType 去决定是否「复用」,举个很老的官方例子,如下图片代码里的 StatelessColorfulTile
所示,它是一个无状态的 StatelessWidget ,显示了一个随机颜色的 200x200 大小的正方形,通过点击右下角按键,每次调整两个方块的位置,可以看到方块可以正常切换:
因为此时没有 Key ,在 Element Tree 只需要判断 runtimeType ,明显此时 Element 符合复用条件,而代码里又是直接使用 StatelessColorfulTile
的 Widget 实例对象进行 tiles.insert(1, tiles.removeAt(0))
,所以在 Widget 切换位置之后,Element 和 RenderObject 只需要 update 一下新位置 Widget 实例的颜色即可:
但是,如果我们修改为 StatefulWidget ,此时我们再点击右下角按键,可以看到此时颜色方块不会切换了:
因为此时颜色 color 被保存在 State 下,在 Widget 切换位置之后,因为 runtimeType 符合条件,所以 Element 复用,但是颜色被保存在 State 下,State 又是保存在 Element 里,从而导致颜色并没有按照需求被更新切换:
但是,如果这时候我们给两个 StatefulWidget 添加上 Key ,就可以看到它们可以被切换了,因为 canUpdate
判断条件会增加 Key 判断:
也就是,在有了 Key 之后,新 Widget 的 key 就可以在老 Element 列表里进行匹配,从而更新 Element 的位置并刷新 RenderObject,两个 Element 在状态保留的情况下,被 Tree 里调换了位置进行更新,从而实现了切换的效果:
所以,从这个简单的例子,可以直观看到 Key 在有状态的情况下能够发挥的作用,当然,目前在 Flutter 里的 Key 类型很丰富,但是大致可以简单分为两类: Local Keys 和 Global Keys 。
顾名思义就是它的作用范围,举个例子,如果我们给 StatelessColorfulTile
增加了一个 Padding ,再点击切换按键,可以看到此时点击后 Element 一直被重构:
因为此时在 Row
里面,此时处于“一级”位置 children 是两个 Padding,而 Padding 没有 Key,所以它在 runtimeType 条件的情况下,是直接被复用:
而对于 StatelessColorfulTile
而言,它处于 Padding 之下,Padding 不是一个 Multi Child 的控件,所以在 canUpdate 为 false 的时候,Flutter 内部会认为它需要被重新创建:
从这里我们就可以很直观体验到 Local Keys 这个概念:它只作用于标识同一父 Widget 中的 Widget,不能用于识别其父 Widget 之外的 Widget。
同时,我们也可以是直观感受到:Multi Child 和 Single Child 的 Element 对于 Diff 更新时的策略差别。
另外,我们还可以感受到 Widget 作为「配置文件」的存在,要知道,代码里我们操作的一直都是 tiles.insert(1, tiles.removeAt(0));
,也就是 Widget 的实例化都的对象,虽然 Widget 实例没变,但是 Element 层面还是会根据情况「重新创建」对应的 Element ,由于颜色是在 State 里,所以也就会跟着 Element 重新随机变化。
最后如下图所示,对于 Local Keys 来说,左侧这样的写法是可以的,而右侧这样的写法是违规的:
所以,在 Widget 的 Key 注释里也有这样一句描述:通常情况下,作为另一个 widget 的唯一子项的 widget 不需要显式 Key。
GlobalKey
那么,除开 Local Keys ,Flutter 里还有一个特殊的 GlobalKey,允许开发者在 Widget 树里去「唯一」标识 Widget,并提供 BuildContext(Element)/State 的全局访问:
这里的「唯一」更多体现在当前这一帧里的「唯一」。
比如前面的例子,我们只需要把对应的 Local Keys 换成 GlobalKey ,就可以看到,虽然 Key 所在的 StatelessColorfulTile
还是在 Padding 下的“二级” child ,但是现在点击切换时,它不会被「重新创建」导致颜色发生变化:
这是因为,虽然在 updateChild
的时候,逻辑依然会走到 inflateWidget
去创建 Element ,但是由于是 GlobalKey,所以会从全局保存的 Map 里获取到当前 GlobalKey 绑定的 Element ,从而 retake 复用:
从这里可以看出来, 如果 Element 在同一帧中移动或者删除,并且它具有 GlobalKey,那么它仍然可能被重新激活使用。
所以 GlobalKey 不仅可以作为 Key 区分 Widget ,帧内还可以在 BuildOwner 里“全局”保持住 Element 、State 和关联 RenderObject 的“状态”,即使它出现移动或者删除。
同时,通过 GlobalKey ,我们也可以访问对应的 BuildContext 和 State 数据,甚至是直接给 MaterialApp
添加 GlobalKey 来操作导航:
那么 GlobalKey 这么好用,它又存在什么问题呢?其实在注释里已经有对应说明:
GlobalKey 在使用的过程中可能会出现需要重新设置 [Element] 父级的情况,而这个操作会触发对关联的 [State] 及其所有后代 [State.deactivate] 的调用,还会强制重建所有依赖于 [InheritedWidget] 的控件。
具体就体现在这下面两段代码:
_retakeInactiveElement
内可能会触发所有关联 State 的deactivate
_activateWithParent
会触发 Element 的activate
,从而通过didChangeDependencies
强制重建所有依赖于 [InheritedWidget] 的控件
当然,GlobalKey 也有一些注意事项,例如:
使用 GlobalKey 不能频繁创建,通常应该是让它和 State 对象拥有类似的“生命长度”,因为新的 GlobalKey 会丢弃与旧 Key 关联的子树的状态,并为新键创建一个新的子树,频繁创建会导致状态丢失和性能损耗。
变更提议
前面我们主要介绍了 Key 的作用和分类下的职能,而本次 PR 提议的调整,则是在于打算简化 Local Keys 相关的实现上,可以看到在以往的实现里,关于 LocalKey 的实现有好几种类型,但是其中一些职能其实「相对重复」:
在 #159225 的 PR 里,将打算把 Key 对象切换到 Object ,从而“消灭”过往这些 Local Keys 的“重叠”,让 Key API 更加灵活:
另外,除了灵活和简化之外,针对目前存在的 Local Keys ,它和 Dart 的 Extension Types 不同,比如使用 ValueKey() 多多少少会有一点点点点点点 wrapper 成本,而如果这个提议合并后,大概会是如下所示的情况,或多或少对性能还是有那么一点点点点点点帮助:
事实上对于 LocalKey ,大多数人应该都只会使用到
ValueKey
居多。
当然,这个 PR 整体来说还是属于底层大调整,而目前看起来提议应该是暂时搁置了,不过就算推进落地,相信对于大多数上层 Flutter 开发者来说,应该也不会有明显的感知,毕竟大多数时候 Flutter 开发者对 Key 并不敏感:
所以,你是喜欢现在的 Local Keys 分类还是提议里的 Object ?
参考链接:
- https://github.com/flutter/flutter/pull/159225
- https://api.flutter.dev/flutter/foundation/Key-class.html
相关文章:
Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用
Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用 在 Flutter 里,Key 对象存在的目的主要是区分和维持 Widget 的状态,它是控件在渲染树里的「复用」标识之一,这一点在之前的《深入 Flutter 和 Compose 在 UI 渲染刷新时…...
src和href区别
src和href区别 (1)请求资源类型不同(2)作用结果不同(3)解析方式不同 (1)请求资源类型不同 href 用来建立文档和元素之间的链接(是引用),常用的有a、linksrc 在请求src资源时候会将指向的资源下载并且应用到文档中(引入),常用的有script、iframe、image。 (2)作用结果不同 hr…...
STM32之SG90舵机控制
目录 前言: 一、硬件准备与接线 1.1 硬件清单 1.2 接线 二、 SG90舵机简介 1.1 外观 1.2 基本参数 1.3 引脚说明 1.4 控制原理 1.5 特点 1.6 常见问题 三、 单片机简介 四、 程序设计 4.1 定时器配置 4.2 角度控制函数 4.3 主函数调用 五、 总结 …...
尚硅谷课程【笔记】——大数据之Hadoop【一】
课程视频链接:尚硅谷Hadoop3.x教程 一、大数据概论 1)大数据概念 大数据(Big Data):指无法再一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发…...
QEMU 搭建 Ubuntu x86 虚拟机
1. 安装 QEMU 在 Ubuntu 系统中,可以通过以下命令安装 QEMU: sudo apt-get update sudo apt-get install qemu-system-x86_64 qemu-kvm libvirt-daemon libvirt-clients bridge-utils virt-manager2. 创建虚拟硬盘镜像 qemu-img create -f raw ubuntu…...
mac 意外退出移动硬盘后再次插入移动硬盘不显示怎么办
第一步:sudo ps aux | grep fsck 打开mac控制台输入如下指令,我们看到会出现两个进程,看进程是root的这个 sudo ps aux|grep fsck 第二步:杀死进程 在第一步基础上我们知道不显示u盘的进程是:62319,我们…...
Acwing-基础算法课笔记之基础算法(双指针)
Acwing-基础算法课笔记之基础算法(双指针) 一、双指针算法概念二、关于双指针的一个问题三、模板 一、双指针算法概念 双指针(又称尺取法)是一个常用的优化技巧,用来解决序列的区间问题。 两个指针i,j&am…...
PCIE基础学习
PCIE PIO模式: 一个CPU传输一个32bit给PCIE(IP)。CPU直接与PCIE做数据传输。 DMA模式: CPU通过PCIE bridge 与多个PCIE设备连接,CPU发送命令给桥,桥控制PCIE与memory直接数据连接。 tlp报文 读报文 …...
架构——Nginx功能、职责、原理、配置示例、应用场景
以下是关于 Nginx 的功能、职责、原理、配置示例、应用场景及其高性能原因的详细说明: 一、Nginx 的核心功能 1. 静态资源服务 功能:直接返回静态文件(如 HTML、CSS、JS、图片、视频等)。配置示例:server {listen 80…...
【教程】比亚迪车机接入AI大模型语音助手
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 更新说明: v1.1.0.2 1、新增长按音量键触发,不再需要迪加 (需设置modelisten)。 2、新增kimi、豆包、ChatGPT等多个GPT接口。 3…...
ios中常见的设计原则和设计模式
七大设计原则 1:开闭原则 对扩展开放,对修改关闭,在设计模块的时候,使模块在不被修改的前提下可以扩展功能 2:依赖倒置原则 实现尽量依赖抽象,不依赖具体实现 (1)高层模块不应该依赖底层模…...
WSL Ubuntu 安装 CUDA 教程
WSL Ubuntu 安装 CUDA 教程 1. 概述2. 准备工作3. 删除旧的 GPG 密钥4. 安装 CUDA Toolkit4.1 使用 WSL-Ubuntu 包安装(推荐) 5. 设置环境变量6. 注意事项7. 参考链接8. 总结 1. 概述 随着 WSL 2 的推出,Windows 用户现在可以在 Windows 子系…...
案例-02.部门管理-查询
一.查询部门-需求 二.查询部门-思路 API接口文档 三.代码实现 1.controller层:负责与前端进行交互,接收前端所发来的请求 注:Slf4j用于记录日志使用,可以省略private static Logger log LoggerFactory.getLogger(DeptControlle…...
【ARM】解决ArmDS Fast Models 中部分内核无法上电的问题
1、 文档目标 解决ArmDS Fast Models 中部分内核无法上电的问题。 2、 问题场景 在调用ArmDS的Fast Models中的Cortex-A55的模型,只有Core 0是上电状态,而Core 1处于掉电状态,如图2-1所示: 图2-1 3、软硬件环境 1)…...
docker 基础命令使用(ubuntu)
docker 状态查询 docker ps docker ps -adocker --version docker info docker --help docker run --help docker ps --help ...docker 操作镜像命令 docker imagesdocker rmi 镜像id/镜像名docker 操作容器命令 docker ps docker ps -adocker run 命令 # 端口映射 -p 参数…...
WEB安全--SQL注入--二次注入
一、原理: 二次注入的关键在于攻击者的输入并不立即执行,而是经过某些存储或处理后,在后续某个步骤中再触发注入攻击 二、示例: 2.1、sqli-labs-master/less-24: admin# 第一次在网页注册账号和密码时没有漏洞&#x…...
c++中什么时候应该使用final关键字?
在C中,final关键字是自C11标准引入的重要特性,主要用于类继承和虚函数重写机制的约束。下面从技术原理、使用场景和最佳实践三个维度进行系统分析,并给出工业级代码示例。 目录 一、技术原理深度解析 二、关键使用场景分析 1. 类级别的fi…...
DeepSeek学术秘籍:如何让DeepSeek辅助论证?
随着人工智能技术的飞速发展,AIGC技术在学术领域的应用逐渐引起了广泛关注。其中最近大火的DeepSeek作为一款基于大语言模型的应用,其出现标志着学术论文写作中研究方法的一次重大变革。 辅助论证 在学术论文写作中,借助DeepSeek优化辅助论证…...
Atlassian工具集:Jira与Confluence集成优势、使用技巧、更新功能等
本文由Atlassian全球白金合作伙伴-龙智翻译整理,深入探讨了Jira和Confluence最受欢迎的集成功能与技巧,期待为您新一年的团队协作开个好头。 此前,来自K15t 的Customer Advocate Matt Reiner 和Atlassian副产品经理David Olive在一场学习会议…...
传输层协议TCP ( 下 )
文章目录 前言序号与确认序号超时重传RTOJacobson算法内核中超时时间的计算 滑动窗口滑动窗口延迟应答流量控制 拥塞控制慢启动拥塞避免快重传快速恢复 保活机制参考资料 前言 TCP(Transmission Control Protocol,传输控制协议)是互联网最重要…...
【Deepseek 零门槛指南】DeepSeek 教程和常见问题解答 | 大白技术控
粉丝朋友们大家好,我是极客学长。最近一直在玩 DeepSeek,积累了一点经验,用它提高写作的效率挺好用的。 在使用DeepSeek的过程中,也遇到了如下几个问题(相信很多小伙伴也遇到了): DeepSeek 官网卡顿,突然出…...
ELK组成及实现原理
ELK是由三个主要组件组成的日志处理和搜索平台,分别是: Elasticsearch:Elasticsearch 是一个基于Lucene构建的开源搜索引擎,提供强大的搜索、分析功能。它负责存储和索引所有数据,并提供实时搜索能力。数据可以通过HTT…...
迅为RK3568开发板篇OpenHarmony实操HDF驱动配置LED-LED测试
将编译好的镜像全部进行烧写,镜像在源码根目录 out/rk3568/packages/phone/images/目录下。 烧写完成之后,在调试串口查看打印日志,如下图所示: 然后打开 hdc 工具,运行测试程序,输入“led_test 1”&…...
【C++】IO流
目录 一、C语言的输入与输出二、流是什么三、CIO流3.1 C标准IO流3.2 C文件IO流3.2.1 二进制读写3.2.2 文本读写 四、stringstream的简单介绍结尾 一、C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据…...
前端知识速记--css篇:CSS3中的常见动画及实现方式
前端知识速记–css篇:CSS3中的常见动画及实现方式 常见的CSS3动画 1. 过渡 (Transitions) 过渡是一种非常简单的动画效果,允许你在元素的状态变更时平滑过渡到新状态。 语法格式: transition: property duration timing-function delay;…...
一个根据输入内容过滤下拉选的组件
1.element的select自定义过滤不是很灵,使用了input和dropdown 组件 <template><div class"autocomplete-wrapper"><!-- 使用 el-input 组件 --><el-inputv-model"inputValue"input"handleInput"placeholder&q…...
Java中的分布式(概念说明)
1. 分布式的基本概念 1.1 什么是分布式系统? 分布式系统(Distributed System):由多台服务器(或节点)协同工作,对外提供一个整体服务。不同节点之间通过网络通信来协同处理请求或共享数据&…...
国产编辑器EverEdit - 上下翻滚不迷路(历史编辑位置、历史光标位置回溯功能)
1 光标位置跳转 1.1 应用场景 某些场景下,用户从当前编辑位置跳转到别的位置查阅信息,如果要快速跳转回之前编辑位置,则可以使用光标跳转相关功能。 1.2 使用方法 1.2.1 上一个编辑位置 跳转到上一个编辑位置,即文本修改过的位…...
css简介
一.css-网页的美容师 css也是一种标记语言,主要用于设置HTML页面中的文本内容(字体大小对齐方式),图片外形(宽高 边框样式 边距等)以及版面的布局和外观显示样式。 二.css语法规范 css规则由两个主要的部分构成:选择器以及一条…...
GoC题解(21) 725.画迷宫(下册第4课)
题目描述 真观察下面迷宫图。发现它是一个边长逐渐变长的15边回旋图,边长依次为10、20、30....。 参考答案 int main(){int len0;for(int i1;i<15;i){ len10;pen.fd(len).rt(90); }return 0; } 解题思路 使用一个变量来记录每次循环时应该画多长的边&#…...
DDD该怎么去落地实现(3)通用的仓库和工厂
通用的仓库和工厂 我有一个梦,就是希望DDD能够成为今后软件研发的主流,越来越多研发团队都转型DDD,采用DDD的设计思想和方法,设计开发软件系统。这个梦想在不久的将来是有可能达成的,因为DDD是软件复杂性的解决之道&a…...
sql sqlserver的特殊函数COALESCE和PIVOT的用法分析
一、COALESCE是一个返回参数中第一个非NULL值的函数, 列如:COALESCE(a,b,c,d,e);可以按照顺序取abcde,中的第一个非空数据,abcde可以是表达式 用case when 加ISNULL也可以实现,但是写法复杂了…...
FPGA简介|结构、组成和应用
Field Programmable Gate Arrays(FPGA,现场可编程逻辑门阵列),是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物, 是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,…...
Vue2/Vue3生命周期对比
Vue2的生命周期钩子 beforeCreate 在实例初始化之后,数据观测(data)和事件配置之前调用。此时无法访问 data、methods 等。 created 在实例创建完成后调用。此时可以访问 data、methods,但 DOM 还未生成。 beforeMount 在挂载…...
Spring Boot 携手 DeepSeek:开启智能交互新时代
前言 在当今数字化浪潮汹涌澎湃的时代,人工智能技术正以前所未有的速度改变着我们的生活和工作方式。大语言模型作为人工智能领域的一颗璀璨明星,凭借其强大的自然语言处理能力,为各个行业带来了新的发展机遇。DeepSeek 作为一款性能卓越的大语言模型,以其高效、准确的文本…...
【Elasticsearch】Mapping概述
以下是Elasticsearch中提到的关于Mapping的各模块概述: --- 1.Dynamic mapping(动态映射) 动态映射是指Elasticsearch在索引文档时,自动检测字段类型并创建字段映射的过程。当你首次索引一个文档时,Elasticsearch会根…...
国内Ubuntu离线安装和配置Ollama服务
以下是在 Ubuntu 22.04 系统上,安装Ollama 的完整安装和配置步骤: 1. 准备工作 确保你具备 root 权限,并安装了必要的工具,如 tar、systemctl 等。 2. 创建 Ollama 用户和组 创建一个专门的 ollama 用户和组来运行 Ollama 服务…...
极狐GitLab 17.8 正式发布,多项 DevOps 重点功能解读【二】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...
【开源免费】基于Vue和SpringBoot的旅游管理系统(附论文)
本文项目编号 T 229 ,文末自助获取源码 \color{red}{T229,文末自助获取源码} T229,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
Communications link failure异常分析解决
Communications link failure异常分析解决 异常日志分析与解决常见原因解决方法 异常日志 2025-02-05 14:26:58.750 ERROR [aaeae2435a2749ac0c4af65b6e4db68c] [http-nio-9528-exec-6] o.s.t.i.TransactionAspectSupport.completeTransactionAfterThrowing:680 - Application…...
建造者模式构建对象
目录 一、创建类 二、用法 三、完整代码 一、创建类 Builder public class User {private final String name;private final int age;Builder.Default private String address "Unknown";Builder.Default private String email "N/A"; }二、用法 (1…...
2025 (ISC)²CCSP 回忆录
2025.1.20 广州,周一,我一次性通过了CCSP的考试。 为什么要考证? 个人成长所需 职业热情:做一行爱一行,既然我投入了美好的青春年华到网络安全行业当中,那么对于这个行业最有权威的认证,是肯定…...
代码随想录算法训练营第三十九天| 动态规划03
01 背包问题 二维 代码随想录 视频讲解:带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili 注意点: 1. dp[i][j] 表示从下标为[0-i]…...
对正则表达式说不!!!
可能大家都会和我一样,时常会遇到正则表达式,有时候会忘记某些字符而苦恼。今天就帮助大家克服它,虽然不多,但我认为掌握这些足够了,万变不离其宗,以不变应万变。 一、正则表达式内容分类 1. 字符类 [abc…...
制作Ubuntu根文件
系列文章目录 Linux内核学习 Linux 知识(1) Linux 知识(2) WSL Ubuntu QEMU 虚拟机 Linux 调试视频 PCIe 与 USB 的补充知识 vscode 使用说明 树莓派 4B 指南 设备驱动畅想 Linux内核子系统 Linux 文件系统挂载 QEMU 通过网络实现…...
工作一个月的经历和总结
目录 背景: 过程: 初来乍到: 小试牛刀: 终结篇: 总结: 背景: 通过朋友介绍,来到秦皇岛戴卡兴龙轮毂有限公司,我的朋友在这已经干了将近2年了,说这里比…...
Linux 更改 SSH 默认端口以提升服务器安全
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template 🌺 仓库主页: GitCode︱ Gitee ︱ Github 💖 欢迎点赞 👍 收藏 ⭐评论 …...
C#中反射的原理介绍及常见的应用场景介绍
反射(Reflection)是C#中的一种机制,允许程序在运行时获取类型信息并动态调用其成员。通过反射,程序可以访问程序集、模块、类型及其成员(如方法、属性、字段等),并能在运行时创建对象、调用方法…...
Linux内核中IPoIB驱动的初始化机制深度解析
IP over InfiniBand(IPoIB)是Linux内核中重要的网络协议,允许在InfiniBand(IB)网络上传输IP数据包,广泛应用于高性能计算和存储场景。本文深入分析IPoIB驱动初始化流程,探讨其核心设计及关键技术实现。 一、初始化流程概览 IPoIB驱动的初始化通过ipoib_ndo_init函数入口…...
深度学习框架PyTorch
第一章:机器学习基本概念(附代码) 第二章:KNN算法:从思想到实现(附代码) 第三章:决策树算法:从思想到实现(附代码) 第四章:机器学习简…...