TS泛型,原来就这?
一、泛型是什么?有什么作用?
当我们定义一个变量不确定类型的时候有两种解决方式:
-
使用any
使用any定义时存在的问题:虽然知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势 -
使用泛型
泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。 -
设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。
为了便于大家更好地理解上述的内容,我们来举个例子,在这个例子中,我们将一步步揭示泛型的作用。首先我们来定义一个通用的 identity 函数,该函数接收一个参数并直接返回它:
function identity (value) {return value;
}console.log(identity(1)) // 1
现在,我们将 identity 函数做适当的调整,以支持 TypeScript 的 Number 类型的参数:
function identity (value: Number) : Number {return value;
}console.log(identity(1)) // 1
这里 identity 的问题是我们将 Number 类型分配给参数和返回类型,使该函数仅可用于该原始类型。但该函数并不是可扩展或通用的,很明显这并不是我们所希望的。
我们确实可以把 Number 换成 any,我们失去了定义应该返回哪种类型的能力,并且在这个过程中使编译器失去了类型保护的作用。我们的目标是让 identity 函数可以适用于任何特定的类型,为了实现这个目标,我们可以使用泛型来解决这个问题,具体实现方式如下:
function identity <T>(value: T) : T {return value;
}console.log(identity<Number>(1)) // 1
对于刚接触 TypeScript 泛型的读者来说,首次看到 语法会感到陌生。但这没什么可担心的,就像传递参数一样,我们传递了我们想要用于特定函数调用的类型。
参考上面的图片,当我们调用 identity(1) ,Number 类型就像参数 1 一样,它将在出现 T 的任何位置填充该类型。图中< T >内部的 T 被称为类型变量,它是我们希望传递给 identity 函数的类型占位符,同时它被分配给 value 参数用来代替它的类型:此时 T 充当的是类型,而不是特定的 Number 类型。
其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:
- K(Key):表示对象中的键类型;
- V(Value):表示对象中的值类型;
- E(Element):表示元素类型;
其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U,用于扩展我们定义的 identity 函数:
function identity <T, U>(value: T, message: U) : T {console.log(message);return value;
}console.log(identity<Number, string>(68, "Semlinker"));
除了为类型变量显式设定值之外,一种更常见的做法是使编译器自动选择这些类型,从而使代码更简洁。我们可以完全省略尖括号,比如:
function identity <T, U>(value: T, message: U) : T {console.log(message);return value;
}console.log(identity(68, "Semlinker"));
如你所见,该函数接收你传递给它的任何类型,使得我们可以为不同类型创建可重用的组件。现在我们再来看一下 identity 函数:
function identity <T, U>(value: T, message: U) : T {console.log(message);return value;
}
相比之前定义的 identity 函数,新的 identity 函数增加了一个类型变量 U,但该函数的返回类型我们仍然使用 T。如果我们想要返回两种类型的对象该怎么办呢?针对这个问题,我们有多种方案,其中一种就是使用元组,即为元组设置通用的类型:
function identity <T, U>(value: T, message: U) : [T, U] {return [value, message];
}
虽然使用元组解决了上述的问题,但有没有其它更好的方案呢?答案是有的,你可以使用泛型接口。
二、泛型用法
1、在函数中使用泛型
function test <T> (arg:T):T{console.log(arg);return arg;
}
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true// 使用方式类似于函数传参,传什么数据类型,T就表示什么数据类型, 使用表示,T也可以换成任意字符串。
2、在接口中使用泛型
// 注意,这里写法是定义的方法!!!
interface Search {<T,Y>(name:T,age:Y):T
}let fn:Search = function <T, Y>(name: T, id:Y):T {console.log(name, id)return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型
为了解决刚刚上面提到的问题,首先让我们创建一个用于的 identity 函数通用 Identities 接口:
interface Identities<V, M> {value: V,message: M
}
在上述的 Identities 接口中,我们引入了类型变量 V 和 M,来进一步说明有效的字母都可以用于表示类型变量,之后我们就可以将 Identities 接口作为 identity 函数的返回类型:
function identity<T, U> (value: T, message: U): Identities<T, U> {console.log(value + ": " + typeof (value));console.log(message + ": " + typeof (message));let identities: Identities<T, U> = {value,message};return identities;
}console.log(identity(68, "Semlinker"));
以上代码成功运行后,在控制台会输出以下结果:
68: number
Semlinker: string
{value: 68, message: "Semlinker"}
泛型除了可以应用在函数和接口之外,它也可以应用在类中,下面我们就来看一下在类中如何使用泛型。
3、在类中使用泛型
class Animal<T> {name:T;constructor(name: T){this.name = name;}action<T>(say:T) {console.log(say)}
}
let cat = new Animal('cat');
cat.action('mimi')
在类中使用泛型也很简单,我们只需要在类名后面,使用 <T, …> 的语法定义任意多个类型变量,具体示例如下:
interface GenericInterface<U> {value: UgetIdentity: () => U
}class IdentityClass<T> implements GenericInterface<T> {value: Tconstructor(value: T) {this.value = value}getIdentity(): T {return this.value}}const myNumberClass = new IdentityClass<Number>(68);
console.log(myNumberClass.getIdentity()); // 68const myStringClass = new IdentityClass<string>("Semlinker!");
console.log(myStringClass.getIdentity()); // Semlinker!
接下来我们以实例化 myNumberClass 为例,来分析一下其调用过程:
- 在实例化 IdentityClass 对象时,我们传入 Number 类型和构造函数参数值 68;
- 之后在 IdentityClass 类中,类型变量 T 的值变成 Number 类型;
- IdentityClass 类实现了 GenericInterface< T >,而此时 T 表示 Number 类型,因此等价于该类实现了 GenericInterface< Number > 接口;
- 而对于 GenericInterface< T >接口来说,类型变量 U 也变成了 Number。这里我有意使用不同的变量名,以表明类型值沿链向上传播,且与变量名无关。
- 泛型类可确保在整个类中一致地使用指定的数据类型。比如,你可能已经注意到在使用 Typescript 的 React 项目中使用了以下约定:
type Props = {className?: string...
};type State = {submitted?: bool...
};class MyComponent extends React.Component<Props, State> {...
}
在以上代码中,我们将泛型与 React 组件一起使用,以确保组件的 props 和 state 是类型安全的。
相信看到这里一些读者会有疑问,我们在什么时候需要使用泛型呢?通常在决定是否使用泛型时,我们有以下两个参考标准:
- 当你的函数、接口或类将处理多种数据类型时;
- 当函数、接口或类在多个地方使用该数据类型时。
很有可能你没有办法保证在项目早期就使用泛型的组件,但是随着项目的发展,组件的功能通常会被扩展。这种增加的可扩展性最终很可能会满足上述两个条件,在这种情况下,引入泛型将比复制组件来满足一系列数据类型更干净。
我们将在本文的后面探讨更多满足这两个条件的用例。不过在这样做之前,让我们先介绍一下 Typescript 泛型提供的其他功能。
三、泛型约束
interface Person {name:string;age:number;
}
function student<T extends Person>(arg:T):T {return arg;
}student({name:'lili'});//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
student({ name: "lili" , age:'11'});//不能将类型“string”分配给类型“number”
student({ name: "lili" , age:11});
有时我们可能希望限制每个类型变量接受的类型数量,这就是泛型约束的作用。下面我们来举几个例子,介绍一下如何使用泛型约束。
1、确保属性存在
一个很好的例子是在处理字符串或数组时,我们会假设 length 属性是可用的。让我们再次使用 identity 函数并尝试输出参数的长度:
function identity<T>(arg: T): T {console.log(arg.length); // Errorreturn arg;
}
在这种情况下,编译器将不会知道 T 确实含有 length 属性,尤其是在可以将任何类型赋给类型变量 T 的情况下。我们需要做的就是让类型变量 extends 一个含有我们所需属性的接口,比如这样:
interface Length {length: number;
}function identity<T extends Length>(arg: T): T {console.log(arg.length); // 可以获取length属性return arg;
}
T extends Length 用于告诉编译器,我们支持已经实现 Length 接口的任何类型。之后,当我们使用不含有 length 属性的对象作为参数调用 identity 函数时,TypeScript 会提示相关的错误信息:
identity(68); // Error
// Argument of type '68' is not assignable to parameter of type 'Length'.(2345)
此外,我们还可以使用 , 号来分隔多种约束类型,比如:<T extends Length, Type2, Type3>。而对于上述的 length 属性问题来说,如果我们显式地将变量设置为数组类型,也可以解决该问题,具体方式如下:
function identity<T>(arg: T[]): T[] {console.log(arg.length); return arg;
}// or
function identity<T>(arg: Array<T>): Array<T> { console.log(arg.length);return arg;
}
2、检查对象上的键是否存在
泛型约束的另一个常见的使用场景就是检查对象上的键是否存在。不过在看具体示例之前,我们得来了解一下 keyof 操作符,keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。 “耳听为虚,眼见为实”,我们来举个 keyof 的使用示例:
interface Person {name: string;age: number;location: string;
}type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string | number
通过 keyof 操作符,我们就可以获取指定类型的所有键,之后我们就可以结合前面介绍的 extends 约束,即限制输入的属性名包含在 keyof 返回的联合类型中。具体的使用方式如下:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {return obj[key];
}
在以上的 getProperty 函数中,我们通过 K extends keyof T 确保参数 key 一定是对象中含有的键,这样就不会发生运行时错误。这是一个类型安全的解决方案,与简单调用 let value = obj[key]; 不同。
下面我们来看一下如何使用 getProperty 函数:
enum Difficulty {Easy,Intermediate,Hard
}function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {return obj[key];
}let tsInfo = {name: "Typescript",supersetOf: "Javascript",difficulty: Difficulty.Intermediate
}let difficulty: Difficulty = getProperty(tsInfo, 'difficulty'); // OKlet supersetOf: string = getProperty(tsInfo, 'superset_of'); // Error
在以上示例中,对于 getProperty(tsInfo, ‘superset_of’) 这个表达式,TypeScript 编译器会提示以下错误信息:
Argument of type '"superset_of"' is not assignable to parameter of type
'"difficulty" | "name" | "supersetOf"'.(2345)
很明显通过使用泛型约束,在编译阶段我们就可以提前发现错误,大大提高了程序的健壮性和稳定性。接下来,我们来介绍一下泛型参数默认类型。
3、数组泛型
let arr:Array<number> =[1,2,3] === let arr:number[]=[1,2,3]
四、泛型参数默认类型
在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推断出类型时,这个默认类型就会起作用。
泛型参数默认类型与普通函数默认值类似,对应的语法很简单,即 <T=Default Type>,对应的使用示例如下:
interface A<T=string> {name: T;
}const strA: A = { name: "Semlinker" };
const numB: A<number> = { name: 101 };
泛型参数的默认类型遵循以下规则:
- 有默认类型的类型参数被认为是可选的。
- 必选的类型参数不能在可选的类型参数后。
- 如果类型参数有约束,类型参数的默认类型必须满足这个约束。
- 当指定类型实参时,你只需要指定必选类型参数的类型实参。 未指定的类型参数会被解析为它们的默认类型。
- 如果指定了默认类型,且类型推断无法选择一个候选类型,那么将使用默认类型作为推断结果。
- 一个被现有类或接口合并的类或者接口的声明可以为现有类型参数引入默认类型。
- 一个被现有类或接口合并的类或者接口的声明可以引入新的类型参数,只要它指定了默认类型。
五、泛型条件类型
在 TypeScript 2.8 中引入了条件类型,使得我们可以根据某些条件得到不同的类型,这里所说的条件是类型兼容性约束。尽管以上代码中使用了 extends 关键字,也不一定要强制满足继承关系,而是检查是否满足结构兼容性。
条件类型会以一个条件表达式进行类型关系检测,从而在两种类型中选择其一:
T extends U ? X : Y
以上表达式的意思是:若 T 能够赋值给 U,那么类型是 X,否则为 Y。在条件类型表达式中,我们通常还会结合 infer 关键字,实现类型抽取:
interface Dictionary<T = any> {[key: string]: T;
}type StrDict = Dictionary<string>type DictMember<T> = T extends Dictionary<infer V> ? V : never
type StrDictMember = DictMember<StrDict> // string
在上面示例中,当类型 T 满足 T extends Dictionary 约束时,我们会使用 infer 关键字声明了一个类型变量 V,并返回该类型,否则返回 never 类型。
- 在 TypeScript 中,never 类型表示的是那些永不存在的值的类型。 例如, never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
- 另外,需要注意的是,没有类型是 never 的子类型或可以赋值给 never 类型(除了 never 本身之外)。 即使 any 也不可以赋值给 never。
除了上述的应用外,利用条件类型和 infer 关键字,我们还可以方便地实现获取 Promise 对象的返回值类型,比如:
async function stringPromise() {return "Hello, Semlinker!";
}interface Person {name: string;age: number;
}async function personPromise() {return { name: "Semlinker", age: 30 } as Person;
}type PromiseType<T> = (args: any[]) => Promise<T>;
type UnPromisify<T> = T extends PromiseType<infer U> ? U : never;type extractStringPromise = UnPromisify<typeof stringPromise>; // string
type extractPersonPromise = UnPromisify<typeof personPromise>; // Person
六、泛型工具类型
1、Partial
partial< T >的作用就是将某个类型中的属性全部变为可选项?
interface Person {name:string;age:number;
}
function student<T extends Person>(arg: Partial<T>):Partial<T> {return arg;
}
interface Todo {title: string;description: string;
}function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {return { ...todo, ...fieldsToUpdate };
}const todo1 = {title: "organize desk",description: "clear clutter"
};const todo2 = updateTodo(todo1, {description: "throw out trash"
});
在上面的 updateTodo 方法中,我们利用 Partial< T > 工具类型,定义 fieldsToUpdate 的类型为 Partial< Todo >,即:
{title?: string | undefined;description?: string | undefined;
}
2、Record
Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。
interface PageInfo {title: string
}
type Page = 'home'|'about'|'other';
const x: Record<Page, PageInfo> = {home: { title: "xxx" },about: { title: "aaa" },other: { title: "ccc" },
};
3、Pick
Pick<T, K extends keyof T>的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型,示例:
interface Todo {title:string,desc:string,time:string
}
type TodoPreview = Pick<Todo, 'title'|'time'>;
const todo: TodoPreview ={title:'吃饭',time:'明天'
}
4、Exclude
Exclude<T,U>的作用是将某个类型中属于另一个类型的属性移除掉,示例:
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
const t:T0 ='b';
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number
5、ReturnType
returnType< T >的作用是用于获取函数T的返回类型,示例:
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // {}
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T4 = ReturnType<any>; // any
type T5 = ReturnType<never>; // any
type T6 = ReturnType<string>; // Error
type T7 = ReturnType<Function>; // Error
相关文章:
TS泛型,原来就这?
一、泛型是什么?有什么作用? 当我们定义一个变量不确定类型的时候有两种解决方式: 使用any 使用any定义时存在的问题:虽然知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势 使用泛型 泛型…...
关于算法学习和刷题的建议
大家好,我是方圆。最近花时间学了学算法,应该算是我接触Java以来第一次真正的学习它,这篇帖子我会说一些我对算法学习的理解,当然这仅仅是浅浅的入算法的门,如果想深挖或者是有基础的人想提升自己,我觉得这…...
2023年“网络安全”赛项浙江省金华市选拔赛 任务书
2023年“网络安全”赛项浙江省金华市选拔赛 任务书 任务书 一、竞赛时间 共计3小时。 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段单兵模式系统渗透测试 任务一 Windows操作系统渗透测试 任务二 Linux操作系统渗透测试 任务三 网页渗透 任务四 Linux系统…...
http协议简介
http 1.简介 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处…...
CSDN 第三十一期竞赛题解
第二次参加 总分77.5,主要是在最后一题数据有误,花费了巨量时间… 参加的另一次比赛最后一道题目也出现了一点问题,有点遗憾。 题解 T1:最优利润值 你在读的经营课程上,老师布置了一道作业。在一家公司的日常运营中&…...
EM_ASM系列宏定义(emscripten)
2.5 EM_ASM系列宏很多编译器支持在C/C代码直接嵌入汇编代码,Emscripten采用类似的方式,提供了一组以“EM_ASM”为前缀的宏,用于以内联的方式在C/C代码中直接嵌入JavaScript代码。2.5.1 EM_ASMEM_ASM使用很简单,只需要将欲执行的Ja…...
Batchnorm和Layernorm的区别
在深度学习训练中,我们经常会遇到这两个归一化操作,他们之间有什么区别呢?我们来简单介绍一下: BatchNorm: 在深度学习训练的时候我们的数据如果没有经过预处理,有可能会出现梯度消失或者梯度爆炸的情况&…...
高级前端面试题汇总
iframe 有那些优点和缺点? iframe 元素会创建包含另外一个文档的内联框架(即行内框架)。 优点: 用来加载速度较慢的内容(如广告)可以使脚本可以并行下载可以实现跨子域通信 缺点: iframe 会…...
HTML#5表单标签
一. 表单标签介绍表单: 在网页中主要负责数据采集功能,使用<form>标签定义表单表单项: 不同类型的input元素, 下拉列表, 文本域<form> 定义表单<input> 定义表单项,通过typr属性控制输入形式<label> 为表单项定义标注<select> 定义下拉列表<o…...
ONNX可视化与编辑工具
ONNX可视化与编辑工具netrononnx-modifier在模型部署的过程中,需要使用到ONNX模型,下面给大家推荐两个ONNX可视化与编辑工具,其中,netron仅支持模型的可视化,onnx-modifier支持ONNX的可视化与编辑。 netron Netron是…...
Verilog 学习第五节(串口接收部分)
小梅哥串口部分学习part2 串口通信接收原理串口通信接收程序设计与调试巧用位操作优化串口接收逻辑设计串口接收模块的项目应用案例串口通信接收原理 在采样的时候没有必要一直判断一个clk内全部都是高/低电平,如果采用直接对中间点进行判断的话,很有可能…...
AIX系统常见漏洞修复(exec、rlogin、rsh、ftp、telnet远端服务运行中)
漏洞:1.1 SSH 服务支持弱加密算法 1. 使用telnet 登录2.vi /etc/ssh/sshd_config 最后添加一下内容(去掉 arcfour、arcfour128、arcfour256 等弱加密算法) Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,blowfish-cbc,cast…...
IEEE SLT 2022论文丨如何利用x-vectors提升语音鉴伪系统性能?
分享一篇IEEE SLT 2022收录的声纹识别方向的论文,《HOW TO BOOST ANTI-SPOOFING WITH X-VECTORS》由AuroraLab(极光实验室)发表。 来源丨AuroraLab AuroraLab源自清华大学电子工程系与新疆大学信息科学与工程学院,以说话人识别和…...
设计模式(十三)----结构型模式之桥接模式
1 概述 现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系: 我们可以发现有很多的类,假如我们再增加一个形状或再增加一种颜色,就需要创建更多的类。 试…...
倾向得分匹配案例分析
一、倾向得分匹配法说明 倾向得分匹配模型是由Rosenbaum和Rubin在1983年提出的,首次运用在生物医药领域,后来被广泛运用在药物治疗、计量研究、政策实施评价等领域。倾向得分匹配模型主要用来解决非处理因素(干扰因素)的偏差。 …...
基于SpringCloud的可靠消息最终一致性04:项目基础代码
上一节给出了项目需求和骨架代码,这一节来接着看基础代码。骨架代码和基础代码最主要的区别是:骨架代码都是数据库脚本、POM依赖文件、配置文件内容、运维脚本等,而基础代码则是和业务有关联,但并非关键代码的部分。 这些代码不用一个个地看,主要是看看结构就行。 图二十五…...
操作系统权限提升(十八)之Linux提权-内核提权
Linux 内核提权 Linux 内核提权原理 内核提权是利用Linux内核的漏洞进行提权的,内核漏洞进行提权一般包括三个环节: 1、对目标系统进行信息收集,获取到系统内核信息及版本信息; 2、根据内核版本获取其对应的漏洞以及EXP 3、使…...
华为OD机试真题Java实现【快递运输】真题+解题思路+代码(20222023
快递运输 题目 一辆运送快递的货车,运送的快递均放在大小不等的长方体快递盒中,为了能够装载更多的快递,同时不能让货车超载,需要计算最多能装多少个快递。 注:快递的体积不受限制,快递数最多1000个,货车载重最大50000。 🔥🔥🔥🔥🔥👉👉👉👉👉�…...
java面试题-JVM问题排查
1.常见的Linux定位问题的工具?常见的 Linux 定位问题的命令可以分为以下几类:系统状态命令:包括 top、uptime、vmstat、sar 等命令,用于查看系统整体的状态,如 CPU 使用率、内存使用率、磁盘 I/O 等。进程状态命令&…...
市场上有很多低代码开发平台,不懂编程的人可以用哪些?
市场上有很多低代码开发平台,不懂编程的人可以用哪些?这个问题一看就是外行问的啦,低代码平台主打的就是一个“全民开发”,而且现在很多低代码平台都发展为零代码了,不懂编程也完全可以使用! 所谓低代码开…...
Tina_Linux打包流程说明指南_new
OpenRemoved_Tina_Linux_打包流程_说明指南_new 1 概述 1.1 编写目的 介绍Allwinner 平台上打包流程。 1.2 适用范围 Allwinner 软件平台Tina v3.0 版本以上。 1.3 相关人员 适用Tina 平台的广大客户,想了解Tina 打包流程的开发人员。 2 固件打包简介 固件…...
JVM面试题
JVM 1.jvm的组成部分 类加载器:将javac编译的class文件加载到内存中 运行时数据区:将内存划分成若干个不同的区域。 执行引擎:负责解析命令,提交操作系统执行。 本地接口:融合不同的语言为java所用 2.运行时数据区 方法区&…...
@FeignClient注解
1.在启动类上开启Feign功能 不开会提示找不到所需要的bean Consider defining a bean of type in your configuration SpringBootApplication EnableFeignClients public class AuthApplication {public static void main(String[] args) {SpringApplication.run(AuthApplic…...
一文搞懂如何在 React 中使用 防抖(Debounce)和 节流(Throttle)
在前端的日常开发中,经常会使用到两个函数防抖(Debounce)和节流(Throttle),防抖函数可以有效控制在一段时间内只执行最后一次请求,例如搜索框输入时,只在输入完成后才进行请求接口。…...
Airbyte API
Airbyte API涵盖了Airbyte功能的方方面面,主要分类:Source_definition:来源定义,实现了来源的增删改查功能。Destination_definition:目标定义,实现了目标的增删改查功能。Workspace:工作区管理…...
vue项目使用Electron开发桌面应用
添加npm配置避免安装Electron错误 请确保您的 node 版本大于等于 18. cmd运行: npm config edit 该命令会打开npm的配置文件,请在空白处添加: electron_builder_binaries_mirrorhttps://npmmirror.com/mirrors/electron-builder-binaries/ e…...
std::chrono笔记
文章目录1. radio原型作用示例2. duration原型:作用示例3. time_point原型作用示例4. clockssystem_clock示例steady_clock示例high_resolution_clock先说感觉,这个库真恶心,刚接触感觉跟shi一样,特别是那个命名空间,太…...
接收arp请求并发送回应的实例
本文简单介绍了arp协议,用一个实例查看收到的ARP请求,并对该请求发出ARP回应,实例有完整的源代码,使用C语言在Linux下实现,代码中有详细的注释。 1. ARP协议 ARP(Address Resolution Protocol),地址解析协议;在局域网上通过IP地址获取物理地址MAC的协议,该协议工作在数…...
【高性能计算】TVM使用TE手动优化矩阵乘法算法解析与代码解读
引言 注:本文主要介绍、解释TVM的矩阵优化思想、代码,需要配合代码注释一起阅读。 矩阵乘法是计算密集型运算。为了获得良好的 CPU 性能,有两个重要的优化措施: 提高内存访问的高速缓存命中率。复杂的数值计算和热点内存&#x…...
消息中间件的概念
中间件(middleware)是基础软件的一大类,属于可复用的软件范畴。中间件在操作系统软件,网络和数据库之上,应用软件之下,总的作用是为处于自己上层的应用软件提供运行于开发的环境,帮助用户灵活、高效的开发和集成复杂的…...
如何规避电子政务门户网站建设教训/如何做到精准客户推广
2019独角兽企业重金招聘Python工程师标准>>> 【中国公益在线广州讯 记者张强】10月19日,由中国.尚洋科技、法国.科诗美蒂卡主办,珠海尚妆生物科技有限公司承办,世界旅游辣妈大赛组委会、广东省色妆职业培训学院、南方日报社、广东…...
深圳网站设计排名/正规推广平台
分销系统开发|分销说白了就是让更多的人帮助企业卖货,企业通过一定的返利机制,促使分销员积极裂变推广产品,从而达到快速销售商品的目的。 分销模式一般有三种:一级分销、二级分销和三级分销。 一级分销相比于其他两种࿰…...
28网站怎么做代理/企业seo
linklinklink 分析: 勋章都是222的幂次 所以就是问每个数的二进制有多少个111 CODE: #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define reg register using namespace std; typedef lon…...
学做新疆菜的网站/百度网页浏览器
github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计算总价。 基础版本 price float(input("输入商品单价:")) number int(input("输入商品数…...
广州网站建设技术/淘宝热搜关键词排行榜
服务端的实现:import SimpleXMLRPCServer,osrunningTruefuns[add,minus,exit,getCurrentList,linuxCmd]#new code解决rpc调用速度慢#每次返回的时候BaseHTTPRequestHandler 都会调用log_message 方法记录一些日志信息,而log_message方法需要知道请求的ho…...
单页网站设计制作/企业网站推广方案设计毕业设计
目录useraddpasswduserdelusermodidsusudo1.useradduseradd - create a new user or update default new user information. 命令一般用来创建新用户或更新默认新用户信息。选项-c , --comment COMMENT 给新用户添加备注;-d, -- home-dir HOME_DIR为主目录指定一个名…...