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

源码阅读:classnames

源码阅读:classnames

  • 源码阅读:classnames
    • 简介
    • 源码解读
      • index
      • dedupe
      • bind
      • 类型声明
    • 学习与收获

源码阅读:classnames

简介

classnames 一个简单的 JavaScript 实用程序,用于有条件地将类名连接在一起。

可以通过 npm 包管理器从 npm 注册表上下载:

npm install classnames

classNames 函数接受任意数量的参数,可以是字符串或对象。参数 'foo' 是 { foo: true } 的缩写。如果与给定键关联的值是假的,则该键将不会包含在输出中。

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'// 支持不同类型的参数同时传入
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'// 数组将按照上述规则递归展平
const arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'
// 相当于
classNames('a', 'b', { c: true, d: false }); // => 'a b c'let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });

在 React 中使用:
下面这段代码实现了一个具有交互功能的按钮组件。按钮的样式类名将根据按钮的状态动态改变,从而实现按钮按下和鼠标悬停的反馈效果。

import React, { useState } from 'react';export default function Button (props) {const [isPressed, setIsPressed] = useState(false);const [isHovered, setIsHovered] = useState(false);let btnClass = 'btn';if (isPressed) btnClass += ' btn-pressed';else if (isHovered) btnClass += ' btn-over';return (<buttonclassName={btnClass}onMouseDown={() => setIsPressed(true)}onMouseUp={() => setIsPressed(false)}onMouseEnter={() => setIsHovered(true)}onMouseLeave={() => setIsHovered(false)}>{props.label}</button>);
}

而使用classnames库来动态生成按钮的类名:

import React, { useState } from 'react';
import classNames from 'classnames';export default function Button (props) {const [isPressed, setIsPressed] = useState(false);const [isHovered, setIsHovered] = useState(false);const btnClass = classNames({btn: true,'btn-pressed': isPressed,'btn-over': !isPressed && isHovered,});return (<buttonclassName={btnClass}onMouseDown={() => setIsPressed(true)}onMouseUp={() => setIsPressed(false)}onMouseEnter={() => setIsHovered(true)}onMouseLeave={() => setIsHovered(false)}>{props.label}</button>);
}
  • 'btn: true':键为btn,表示按钮应该包含类名 btn
  • 'btn-pressed': isPressed:键为btn-pressed,表示当isPressedtrue时,按钮应该包含类名btn-pressed
  • 'btn-over': !isPressed && isHovered:键为btn-over,表示当isPressedfalseisHoveredtrue时,按钮应该包含类名btn-over

因为可以将对象、数组和字符串参数混合在一起,所以支持可选的 className prop属性也更简单,因为结果中只包含真实参数:

const btnClass = classNames('btn', this.props.className, {'btn-pressed': isPressed,'btn-over': !isPressed && isHovered,
});

此外,作者还提供了另外两个版本:dedupe 版本和 bind 版本。

其中dedupe 版本可以正确地删除类的重复数据,并确保从结果集中排除后面参数中指定的虚假类。但是此版本速度较慢(大约 5 倍),因此它作为一个可选的版本。

const classNames = require('classnames/dedupe');classNames('foo', 'foo', 'bar'); // => 'foo bar'
classNames('foo', { foo: false, bar: true }); // => 'bar'

而另一个bind 版本可以让你结合 css-modules,以便在组件中动态地添加或删除 CSS 类名,同时保证 css-modules 的作用域。

css-modules 是一种在项目中使用局部作用域的 CSS 的方法。它通过给每个类名添加一个唯一的哈希值,确保类名在整个应用程序中是唯一的,避免了全局作用域的类名冲突。

const classNames = require('classnames/bind');const styles = {foo: 'abc',bar: 'def',baz: 'xyz',
};const cx = classNames.bind(styles);const className = cx('foo', ['bar'], { baz: true }); // => 'abc def xyz'

下面是一个使用classnamesbind版本结合css-modules的示例:

import { useState } from 'react';
import classNames from 'classnames/bind';
import styles from './submit-button.css';const cx = classNames.bind(styles);export default function SubmitButton ({ store, form }) {const [submissionInProgress, setSubmissionInProgress] = useState(store.submissionInProgress);const [errorOccurred, setErrorOccurred] = useState(store.errorOccurred);const [valid, setValid] = useState(form.valid);const text = submissionInProgress ? 'Processing...' : 'Submit';const className = cx({base: true,inProgress: submissionInProgress,error: errorOccurred,disabled: valid,});return <button className={className}>{text}</button>;
}

源码解读

由于代码比较短,这里便直接放源码,并在其中加上了注释,读者可自行阅读:

index

/*!Copyright (c) 2018 Jed Watson.Licensed under the MIT License (MIT), seehttp://jedwatson.github.io/classnames
*/
/* global define */(function () {'use strict';var hasOwn = {}.hasOwnProperty;function classNames() {// 用于存储生成的类名数组var classes = [];for (var i = 0; i < arguments.length; i++) {// 获取当前参数var arg = arguments[i];// 如果参数为空或为false,则跳过if (!arg) continue;// 获取参数的类型var argType = typeof arg;// 如果参数是字符串或数字,则直接添加到类名数组中if (argType === 'string' || argType === 'number') {classes.push(arg);} else if (Array.isArray(arg)) {if (arg.length) {// 如果参数是数组,则递归调用classnames函数,并将数组作为参数传入var inner = classNames.apply(null, arg);if (inner) {// 如果递归调用的结果不为空,则将结果添加到类名数组中classes.push(inner);}}} else if (argType === 'object') {// 判断 object 是否是一个自定义对象// 因为原生的 JavaScript 对象(例如 Array、Object 等)的 toString 方法包含 [native code]if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {classes.push(arg.toString());continue;}for (var key in arg) {if (hasOwn.call(arg, key) && arg[key]) {// 如果参数是对象,并且对象的属性值为真,则将属性名添加到类名数组中classes.push(key);}}}}// 将类名数组通过空格连接成字符串,并返回return classes.join(' ');}// 判断是否在CommonJS环境下,如果是,则将classNames赋值给module.exportsif (typeof module !== 'undefined' && module.exports) {classNames.default = classNames;module.exports = classNames;} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// 如果在AMD环境下,则将classnames函数注册为模块,并将其命名为'classnames'define('classnames', [], function () {return classNames;});} else {// 在浏览器环境下,将classnames函数挂载到全局的window对象上window.classNames = classNames;}
}());

dedupe

/*!Copyright (c) 2018 Jed Watson.Licensed under the MIT License (MIT), seehttp://jedwatson.github.io/classnames
*/
/* global define */(function () {'use strict';var classNames = (function () {// 创建一个不继承自Object的空对象,以便后面可以跳过hasOwnProperty的检查function StorageObject() {}StorageObject.prototype = Object.create(null);// 解析数组,将数组中的每个元素解析为classNamesfunction _parseArray (resultSet, array) {var length = array.length;for (var i = 0; i < length; ++i) {_parse(resultSet, array[i]);}}var hasOwn = {}.hasOwnProperty;// 解析数字,将数字作为classNames的属性function _parseNumber (resultSet, num) {resultSet[num] = true;}// 解析对象,将对象的属性作为classNames的属性function _parseObject (resultSet, object) {// 判断 object 是否是一个自定义对象// 因为原生的 JavaScript 对象(例如 Array、Object 等)的 toString 方法包含 [native code]if (object.toString !== Object.prototype.toString && !object.toString.toString().includes('[native code]')) {resultSet[object.toString()] = true;return;}for (var k in object) {if (hasOwn.call(object, k)) {// set value to false instead of deleting it to avoid changing object structure// https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/#de-referencing-misconceptionsresultSet[k] = !!object[k];}}}var SPACE = /\s+/;// 解析字符串,将字符串按照空格分割为数组,并将数组中的每个元素作为classNames的属性function _parseString (resultSet, str) {var array = str.split(SPACE);var length = array.length;for (var i = 0; i < length; ++i) {resultSet[array[i]] = true;}}// 解析参数,根据参数的类型调用相应的解析函数function _parse (resultSet, arg) {if (!arg) return;var argType = typeof arg;// 处理字符串类型的参数// 'foo bar'if (argType === 'string') {_parseString(resultSet, arg);// 处理数组类型的参数// ['foo', 'bar', ...]} else if (Array.isArray(arg)) {_parseArray(resultSet, arg);// 处理对象类型的参数// { 'foo': true, ... }} else if (argType === 'object') {_parseObject(resultSet, arg);// 处理数字类型的参数// '130'} else if (argType === 'number') {_parseNumber(resultSet, arg);}}// 主函数function _classNames () {// 避免arguments泄漏var len = arguments.length;var args = Array(len);for (var i = 0; i < len; i++) {args[i] = arguments[i];}// 创建一个存储classNames的对象var classSet = new StorageObject();// 解析参数并将结果存储在classSet对象中_parseArray(classSet, args);var list = [];// 将classSet中值为true的属性加入到list数组中for (var k in classSet) {if (classSet[k]) {list.push(k)}}return list.join(' ');}return _classNames;})();// 判断是否在CommonJS环境下,如果是,则将classNames赋值给module.exportsif (typeof module !== 'undefined' && module.exports) {classNames.default = classNames;module.exports = classNames;} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// 如果在AMD环境下,则将classnames函数注册为模块,并将其命名为'classnames'define('classnames', [], function () {return classNames;});} else {// 在浏览器环境下,将classnames函数挂载到全局的window对象上window.classNames = classNames;}
}());

bind

/*!Copyright (c) 2018 Jed Watson.Licensed under the MIT License (MIT), seehttp://jedwatson.github.io/classnames
*/
/* global define */(function () {'use strict';var hasOwn = {}.hasOwnProperty;function classNames () {// 用于存储生成的类名数组var classes = [];for (var i = 0; i < arguments.length; i++) {// 获取当前参数var arg = arguments[i];// 如果参数为空或为false,则跳过if (!arg) continue;var argType = typeof arg;// 如果参数是字符串或数字,则直接添加到类名数组中if (argType === 'string' || argType === 'number') {classes.push(this && this[arg] || arg);} else if (Array.isArray(arg)) {// 如果参数是数组,则递归调用classnames函数,并将数组作为参数传入classes.push(classNames.apply(this, arg));} else if (argType === 'object') {// 判断 object 是否是一个自定义对象// 因为原生的 JavaScript 对象(例如 Array、Object 等)的 toString 方法包含 [native code]if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {classes.push(arg.toString());continue;}for (var key in arg) {if (hasOwn.call(arg, key) && arg[key]) {// 如果参数是对象,并且对象的属性值为真,则将属性名添加到类名数组中classes.push(this && this[key] || key);}}}}return classes.join(' ');}// 判断是否在CommonJS环境下,如果是,则将classNames赋值给module.exportsif (typeof module !== 'undefined' && module.exports) {classNames.default = classNames;module.exports = classNames;} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// 如果在AMD环境下,则将classnames函数注册为模块,并将其命名为'classnames'define('classnames', [], function () {return classNames;});} else {// 在浏览器环境下,将classnames函数挂载到全局的window对象上window.classNames = classNames;}
}());

index.js 相比,这个版本增加了对this上下文的处理。

类型声明

// 以下类型声明主要用于定义一个名为 "classNames" 的命名空间和相关的类型。
// 在这个声明中,"classNames" 命名空间中定义了一些类型和接口
declare namespace classNames {// "Value" 是一个联合类型,表示可以接受的值的类型,包括字符串、数字、布尔值、未定义和空值type Value = string | number | boolean | undefined | null;// "Mapping" 是一个类型别名,表示一个键值对的集合,其中键是字符串,值可以是任何类型type Mapping = Record<string, unknown>;// "ArgumentArray" 是一个接口,继承自数组类型 "Array<Argument>",表示一个参数数组,其中每个元素都是 "Argument" 类型interface ArgumentArray extends Array<Argument> {}// "ReadonlyArgumentArray" 是一个接口,继承自只读数组类型 "ReadonlyArray<Argument>",表示一个只读的参数数组interface ReadonlyArgumentArray extends ReadonlyArray<Argument> {}// "Argument" 是一个联合类型,表示可以作为参数的类型,可以是 "Value"、"Mapping"、"ArgumentArray" 或 "ReadonlyArgumentArray"type Argument = Value | Mapping | ArgumentArray | ReadonlyArgumentArray;
}// 定义了一个名为 "ClassNames" 的接口,它是一个函数类型,可以接受 "classNames.ArgumentArray" 类型的参数,并返回一个字符串
interface ClassNames {(...args: classNames.ArgumentArray): string;default: ClassNames;
}declare const classNames: ClassNames;// 通过 "export as namespace" 来将 "classNames" 声明为全局命名空间
export as namespace classNames;
// 使用 "export =" 来导出 "classNames",使其可以在其他模块中使用
export = classNames;

学习与收获

  1. 使用严格模式

在源码开头使用严格模式的主要原因是为了确保代码的质量和可靠性。严格模式可以帮助开发者避免一些常见的错误和不规范的语法,同时也提供了更严格的错误检查和更清晰的错误提示。使用严格模式可以减少一些隐患,提高代码的可维护性和可读性。

此外,严格模式还可以禁止一些潜在的危险行为,例如禁止使用未声明的变量、禁止对只读属性赋值、禁止删除变量等。这可以提高代码的安全性,减少一些潜在的漏洞和安全风险。

因此,为了确保代码的质量、可靠性和安全性,许多开发者选择在源码开头使用严格模式。这样可以强制要求代码符合更严格的规范,减少错误和潜在的问题,并提高代码的可维护性和可读性。

  1. 创建一个不继承自 Object 的空对象

Object.create(null) 是一个创建一个新对象的方法,该对象没有原型链,也就是没有继承任何属性和方法。这意味着该对象没有内置的属性和方法,只能通过直接赋值来添加属性和方法。使用 Object.create(null) 创建的对象被称为“纯净对象”或“字典对象”,它适用于需要一个纯粹的键值对集合而不需要继承的场景。在这种对象中,键和值可以是任何类型的数据,而不仅限于字符串。

在代码中使用了 StorageObject.prototype = Object.create(null); 创建了一个不继承自 Object 的空对象 StorageObject。这样可以跳过 hasOwnProperty 的检查,提高代码的性能。

  1. 解析不同类型的参数,包括字符串、数组、对象和数字

  2. 设计模式

单例模式是一种创建型设计模式,用于确保某个类只有一个实例,并提供一个全局访问点来访问该实例。

  • 单例模式:通过立即执行函数包裹代码,在执行函数内部创建了一个classNames对象,并将其赋值给全局变量window.classNames。这样就保证了只有一个classNames对象存在,其他地方无法再创建新的classNames对象。

工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但具体创建的对象类型可以在运行时确定。工厂模式可以分为简单工厂模式、工厂方法模式和抽象工厂模式。

  1. 简单工厂模式:也称为静态工厂模式,它直接使用一个静态方法来创建对象。
  2. 工厂方法模式:也称为虚拟工厂模式,它定义了一个工厂接口,并由不同的具体工厂实现来创建不同的对象。
  • 工厂模式:通过工厂函数_classNames()创建classNames对象,该对象可以根据不同的参数类型调用不同的解析函数来解析参数,并将结果存储在classSet对象中。
  1. 判断运行环境并导出 classNames

根据不同的运行环境,判断是否在 CommonJS 环境下、AMD 环境下或浏览器环境下。如果在 CommonJS 环境下,将 classNames 赋值给 module.exports;如果在 AMD 环境下,将 classNames 注册为模块,并命名为 'classnames';如果在浏览器环境下,将 classNames 挂载到全局的 window 对象上。

  1. TypeScript 类型声明
  • 命名空间声明:使用declare namespace可以定义一个命名空间,将相关的类型和接口组织在一起,防止命名冲突并提供模块化的结构。
  • 类型别名和联合类型:使用 type 关键字可以定义类型别名,方便重复使用复杂的类型。联合类型可以用于表示一个值可以是多个不同类型之一。
  • 接口和继承:使用 interface 关键字可以定义接口,表示一种对象的结构。接口可以继承自其他接口,通过继承可以复用已有的接口定义。
  • 函数类型:可以使用接口来定义函数类型,指定函数的参数类型和返回值类型。
  • 类型导出和模块导入:使用 export 关键字可以将类型或值导出,使其可以在其他模块中使用。使用 import 关键字可以在其他模块中导入已导出的类型或值。

相关文章:

源码阅读:classnames

源码阅读&#xff1a;classnames 源码阅读&#xff1a;classnames简介源码解读indexdedupebind类型声明 学习与收获 源码阅读&#xff1a;classnames 简介 classnames 一个简单的 JavaScript 实用程序&#xff0c;用于有条件地将类名连接在一起。 可以通过 npm 包管理器从 n…...

【解惑笔记】树莓派+OpenCV+YOLOv5目标检测(Pytorch框架)

【学习资料】 子豪兄的零基础树莓派教程https://github.com/TommyZihao/ZihaoTutorialOfRaspberryPi/blob/master/%E7%AC%AC2%E8%AE%B2%EF%BC%9A%E6%A0%91%E8%8E%93%E6%B4%BE%E6%96%B0%E6%89%8B%E6%97%A0%E7%97%9B%E5%BC%80%E6%9C%BA%E6%8C%87%E5%8D%97.md#%E7%83%A7%E5%BD%95…...

PostgreSQL中如何配置Huge page的数量

在了解如在PG中如何配置大页之前&#xff0c;我们先要对大页进行一定的了解&#xff0c;为什么要配置大页&#xff0c;配置大页的好处有哪些。 我们日常的操作系统中&#xff0c;程序不直接使用内存&#xff0c;而是使用虚拟内存地址来处理内存分配&#xff0c;避免计算的复杂…...

Mysql之binlog日志浅析

一、binlog日志简介 Binlog是MySQL数据库中的二进制日志&#xff0c;用于记录数据库中所有修改操作&#xff0c;包括增删改等操作。binlog以二进制格式保存&#xff0c;可以通过解析binlog文件来查看数据库的操作历史记录。binlog日志可以用于数据恢复、数据备份、数据同步等场…...

js 生成器函数

生成器函数&#xff08;Generator Function&#xff09;&#xff1a;生成器函数是一种特殊的函数&#xff0c;可以通过yield关键字来暂停和恢复函数的执行&#xff0c;从而实现惰性计算和迭代器的功能。在例子中&#xff0c;我们定义了一个fibonacci生成器函数&#xff0c;它使…...

HCIP OSPF+BGP综合实验

题目 1、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中&#xff0c;运行OSPF协议或者BGP协议…...

牛客网Verilog刷题——VL46

牛客网Verilog刷题——VL46 题目解析答案 题目 根据题目提供的双口RAM代码和接口描述&#xff0c;实现同步FIFO&#xff0c;要求FIFO位宽和深度参数化可配置。电路的接口如下图所示。   双口RAM端口说明&#xff1a; 同步FIFO端口说明&#xff1a; 双口RAM代码如下&#xff…...

C/C++开源库推荐

C/C开源库推荐 主要都是平常用到的&#xff0c;包含windows开发、android开发、后台开发、音视频开发、深度学习等等最后还附带几个其他语言开发的比较好的项目 GUI开发 qt 跨平台开发库&#xff0c;内部封装了各种跨平台工具&#xff0c;但是大多数情况下都被用作开发跨平台…...

git常用命令速查表

1.git add -u [<路径>]: 把<路径>中所有跟踪&#xff08;tracked&#xff09;文件中被修改过或已删除文件的信息添加到索引库。它不会处理未跟踪&#xff08;untracked&#xff09;的文件。省略<路径>表示&#xff1a;即当前目录。 2.git add -a [<路径&…...

让两个文件夹里的图片名字一模一样

为了做测试集&#xff0c;对应数据和真值 import os import datetimeimage_names os.listdir(r\Images) #print(image_names) #print(len(image_names))mask_names os.listdir(rG:\Mask) #print(mask_names) #print(len(mask_names))#根据你提供的文件名排序结果来看,问题可…...

会议OA系统会议管理模块开发思路(layui搭建)

目录 一.为什么要进行开发 1.开发目的 2.项目流程 A.发起会议请求过程 1.首先实现我们的多选下拉框功能&#xff01; 2.时间组件功能&#xff0c;并且提交我们新增加的会议内容 3.在进行发起会议编码时遇到的问题&#xff0c;BUG 3.1.有点时候js访问不到路径 3.2在增加…...

rsync 远程同步

目录 一、Rsync 简介 二、同步方式 备份的方式 三、常用Rsync命令 四、配置源的两种表达方法 五、配置服务端与客户端的实验 启动 rsync 服务程序 发起端&#xff08;192.168.158.21&#xff09; ​编辑 六. 发起端&#xff08;客户端&#xff09;配置 rsyncinotify c…...

PostgreSQL数据库中,查询时提示表不存在的解决办法

最近遇到一个奇怪的问题&#xff0c;以前从来没有遇到过&#xff0c;在postgres SCHEMA下执行select * from table1语句时&#xff0c;提示表不存在&#xff0c;而实际这个表确是存在的&#xff0c;只不过是在public SCHEMA下。在public SCHEMA下执行这个sql语句是没有问题的。…...

视频传输网安全防护体系

在电脑、手机信息安全保护得到广泛关注和普及的今天&#xff0c;监控摄像头等设备的安全防护仍为大众所忽略&#xff0c;大量视频监控网络的前端设备和数据没有任何保护&#xff0c;完全暴露在互联网中。 前端IP接入设备与后端业务系统处于直连状态&#xff0c;一旦有攻击者或…...

C# Blazor 学习笔记(1):Blazor基础语法,组件化和生命周期

文章目录 前言基础语法路由Page 页面元素条件生成if / elseforforeach 绑定参数绑定&#xff08;赋值&#xff0c;单向&#xff09;参数绑定&#xff08;双向&#xff09;事件绑定字典绑定 attributes 组件化如何使用Parameter 参数注入使用回调函数组件声明回调组件注入回调组…...

flutter 导出iOS问题2

问题1:The Swift pod FirebaseCoreInternal depends upon GoogleUtilities, which does not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries) 参考 正如上图报错第三方…...

syn报文什么时候会被丢弃?

开启tcp_tw_recycle且在NAT下 tcp_tw_recycle重复利用time_wait sockets&#xff0c;会记录最近的连接时间戳&#xff0c;并丢弃远程主机(PAWS机制)所有不严格大于该时间戳的报文。这意味着如果主机在nat下&#xff0c;那么该nat下所有设备将会受影响 TCP半连接队列满了 在半…...

【C++】开源:Linux端V4L2视频设备库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Linux端V4L2视频设备库。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…...

基于数据驱动的多尺度表示的信号去噪统计方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【Golang】Golang进阶系列教程--Go 语言 map 如何顺序读取?

文章目录 前言现象原因如何顺序读取推荐阅读 前言 Go 语言中的 map 是一种非常强大的数据结构&#xff0c;它允许我们快速地存储和检索键值对。 然而&#xff0c;当我们遍历 map 时&#xff0c;会有一个有趣的现象&#xff0c;那就是输出的键值对顺序是不确定的。 现象 先看…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...