TS函数类型

函数类型表达式

function hello(x: string) {
  console.log(x)
}
//greeter函数的参数是一个函数fn,fn也有一个string类型参数,无返回值。
function greeter(fn: (a: string) => void) {
  fn('hello')
}
greeter(hello)

也可以把定义参数类型的语句单独提取出来。

function hello(x: string) {
  console.log(x)
}
type Hello = (a: string) => void
function greeter(fn: Hello) {
  fn('hello')
}
greeter(hello)

调用签名

上述例子描述了函数可调用性,此外,函数还具有属性。函数表达式不能声明函数的属性,如果我们想描述函数可以做什么,可以为函数设置属性,及调用签名。

type DescriptionFunction = {
  //函数的属性和属性的类型
  description: string
  //(函数参数名:参数类型):函数返回值类型
  (someArg: number): boolean
}
function doSomething(fn: DescriptionFunction) {
  console.log(fn.description + 'returned' + fn(4))
}

function test(someArg: number) {
  return someArg > 3
}
test.description = 'haha'
doSomething(test)

同理你可以自己添加其他属性和参数

type DescriptionFunction = {
  description: string
  total: number
  (someArg: number, otherArg: string): string
}
function doSomething(fn: DescriptionFunction) {
  console.log(fn.description + fn.total + 'returned' + fn(4, 'other'))
}

function test(someArg: number, other: string) {
  return someArg + other
}
test.total = 0
test.description = '函数的描述属性'
doSomething(test)

构造签名

在调用签名中可以使用new关键字来编写构造签名。

type SomeConstructor = {
  new (a: string): object//笼统的说,函数类型是new(string类型的参数),返回值是一个object
}
function constructObj(fn: SomeConstructor) {
  return new fn('string')//调用时也不能少new关键字。
}

可选参数、以及函数参数不同和返回值不同等情况都会导致函数类型不同,你可以使用这些特性来定义一个复杂的函数类型。

//需要保证每种定义不重合。
interface CallOrConstruct {
  (n?: number): string//这个函数可以是不接收参数或接收number参数,并返回string的类型
  (x: string): boolean//这个函数可以是接收string参数返回boolean值的类型
  new (s: string): Date//这个函数可以是构造函数,并且需要接收一个string参数,返回Date值。
}
function doSomeing(fn: CallOrConstruct) {
  //这里只是举例调用,具体能怎么调用,还得看传过来的fn参数带来一些什么样的参数。
  fn(1)
  fn('string')
  new fn('2022-06-01')
}

你可以将上面例子类比于我们经常使用的Date。传时间戳的时候它给我们返回一个时间格式字符串,传某个时间字符串并使用new关键字的时候,他会给我们返回一个日期对象。

泛型函数

当我们的输出类型与输入类型相关时,我们就可以使用泛型函数。
定义方法:使用尖括号定义泛型名称,放在函数名和函数括号中间,现在你可以把定义的泛型类似于一个已知的基础类型来用,用来定义参数和返回值的类型。

function test<Type>(x: Type[]): Type | undefined {
  return x[0]
}
const t1 = test(['1', '2', '3'])//const t1: string | undefined
const t2 = test([1, 2, 3])//const t2: number | undefined
const t3 = test([])//const t3: undefined

你可以使用多个泛型变量
下面编写一个map函数。接收一个数组和一个函数,函数内对接收的数据进行操作,返回值是一个数组。

function myMap<Input, Output>(arr: Input[], func: (a: Input) => Output): Output[] {
  return arr.map(func)//这里调用的是公共的js中的map函数
}
//  const test1: number[]
//在第一个测试案例中,Input类型是number,Output类型是number,返回值类型是number[]
const arr1 = [1, 2, 3]
const test1 = myMap(arr1, (item) => item + 1)
//  const test2: string[]
//在第二个测试案例中,Input是object,output是string,返回值类型是string[]
const arr2 = [
  { id: '12', age: 12 },
  { id: '23', age: 34 }
]
const test2 = myMap(arr2, (item) => item.id)

TypeScript 可以根据函数表达式的返回值推断 Input 类型参数的类型以及 Output 类型参数。
第一次调用myMap,myMap的类型推断为:

function myMap<number, number>(arr: number[], func: (a: number) => number): number[]

第二次调用myMap,myMap的类型推断为:

function myMap<{id: string;age: number;}, string>(arr: {id: string;age: number;}[], func: (a: {id: string;age: number;}) => string): string[]

类型约束

泛型函数可以处理任何类型的值。有时候,我们有两个类型相关的值,但是我们只能操作他的子属性,我们就可以使用类型约束。
下面的test1和test2的类型是根据参数推断出来的。泛型就是将两个或多个具有相同类型的值关联起来!

interface hasLength {
  length: number
}
function longer<Type extends hasLength>(a: Type, b: Type) {
  if (a.length > b.length) return a
  else return b
}
const test1 = longer([1, 2], [1, 2, 3])
const test2 = longer('dfs', 'fdjask')
//const test3 = longer(10, 11)//error,number类型没有length属性

使用约束值的错误

泛型定义的是一种类型,光满足约束的条件不行,还得是真真确确的类型。
让我们看下面这个例子,泛型Type进行了约束,返回值也是Type类型。

function minimumLength<Type extends { length: number }>(obj: Type, minimum: number): Type {
  if (obj.length >= minimum) {
    return obj
  } else {
    return { length: minimum } //error 不能将类型“{ length: number; }”分配给类型“Type”。
  }
}

假设上面的语法合发,将会得到一个完全行不通的代码。

function minimumLength<Type extends { length: number }>(obj: Type, minimum: number): Type {
  if (obj.length >= minimum) {
    return obj
  } else {
    return { length: minimum } //error 不能将类型“{ length: number; }”分配给类型“Type”。
  }
}
//obj.length<minimum,return { length : 4 }
const arr = minimumLength([1, 2, 3], 4)
const x = arr.slice(0)//行不通

分析得知,尽管对象中有length属性,但是对象根本没有slice方法。

指定类型参数

下面是一个将两个数组合并的函数。

function combine<Type>(a: Type[], b: Type[]): Type[] {
  return a.concat(b)
}
combine([1, 2], [3, 4])
combine(['1', '2'], ['3', '4'])
combine([1, 2], ['3', '4'])//error Type已经推断为number类型,后面不能再传string类型的数组了

第三个测试案例中,由于 Type已经推断为number类型,后面不能再传string类型的数组了。
这个时候我们就可以手动指定类型参数的值,而不是让TypeScript给我们默认推断。

//combine([1, 2], ['3', '4'])
combine<number | string>([1, 2], ['3', '4'])

当我们把代码改为上述模样后,可以发现combine的类型推断变为:
实质上这个时候Type的类型就是string|number。

function combine<string | number>(a: (string | number)[], b: (string | number)[]): (string | number)[]

编写良好的泛型函数指南

下推类型参数

如果可以,使用类型参数本身而不是约束它。

function test1<Type>(arr: Type[]) {
  return arr[0]
}
function test2<Type extends any[]>(arr: Type) {
  return arr[0]
}
//const t1: number
const t1 = test1([1, 2, 3])
//const t2: any
const t2 = test2([1, 2, 3])

显然,第一种写法比第二种写法要好,第一种写法可以推断出返回值的类型,而第二种写法推断的类型是any。
我们尽量直接使用类型,而不做类型约束。

使用更少的类型参数

如果可以,始终使用尽可能少的类型参数。
例如写一个过滤函数时,下面第一种写法只定义了一个类型参数,剩下的都是利用这个类型灵活使用,最终调用也能准确地推断出返回值地类型。

function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
  return arr.filter(func)
}
const t1 = filter1([-1, 2, 3], (item) => item > 0)

对于第二种写法,这里多写了一个类型参数Func,还对Func做了类型限制,用起来两者得到的结果是一样的,但是,Func并没有关联两个或多个值的类型,它没有做任何事情,只会让读者更难理解。

function filter2<Type, Func extends (arg: Type) => boolean>(arr: Type[], func: Func): Type[] {
  return arr.filter(func)
}
const t2 = filter2([-1, 2, 3], (item) => item > 0)

类型参数应该出现两次

如果一个类型参数只出现在一个位置,强烈重新考虑是否真的需要它

有时候我们可能忘了函数是不需要泛型的。

function greet<Str extends string>(s: Str) {
  console.log("Hello, " + s);
}
greet("world");

我们可以更容易地编写一个更简单的版本。

function greet(s: string) {
  console.log("Hello, " + s);
}

泛型用于关联多个值的类型。如果一个泛型只在函数签名中使用一次,它就没有任何关系。这包括推断的返回类型;
例如,如果 Str 是 greet 的推断返回类型的一部分,它将关联参数和返回类型,因此尽管在书面代码中只出现一次,但它会被使用两次。

可选参数

//问号,可传可不传,可传undefined
function f1(n?: number): void {
  console.log(n)
}
f1()
f1(1)
f1(undefined)

//指定默认值
function f2(x: number = 10) {
  console.log(x)
}
f2(1)

回调中的可选参数

为回调编写函数类型时,切勿编写可选​​参数,除非你打算在不传递该参数的情况下调用该函数。
如果你在函数类型中声明了一个参数为可选参数,那么在使用这个函数类型时,传递该参数是可选的。如果你不打算在调用函数时传递该参数,但是却在函数类型中将其声明为可选参数,可能会导致一些问题。
这会导致:你有可能传递了可选参数,但是函数里面没有没有调用。或者,你没传递可选参数,但是函数里面调用了。这带来了一些难以查找的错误。

function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
  for (let i = 0; i < arr.length; i++) {
    // callback(arr[i], i)
    callback(arr[i])
  }
}
myForEach([1, 2, 3], (item) => console.log(item))
myForEach([1, 2, 3], (item, index) => console.log(item, index))

函数重载

我们希望可以以各种参数、参数个数、参数类型来调用函数。这可以使用函数重载来实现。
函数签名一定多于两个。
函数只有一个实现签名,但是这个签名不能直接调用。
函数的调用是按照函数的重载签名定义来的,下面两个函数签名中,只有传递一个参数的,或者传递三个参数的。最后一种调用,传递了两个参数,是不可行的。

//函数的重载签名
function makeDate(timestamp: number): Date
function makeDate(m: number, d: number, y: number): Date
//函数的实现签名
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d)
  } else {
    return new Date(mOrTimestamp)
  }
}
//这里调用的都是函数的重载签名,不是函数的实现签名
const d1 = makeDate(1798329749)
const d2 = makeDate(6, 11, 2022)
//error没有需要 2 参数的重载,但存在需要 1 或 3 参数的重载
//const d3 = makeDate(1, 2)

重载签名和实现签名

重载签名:没有方法体,只有函数名、函数参数及类型、函数返回值及类型。
实现签名:兼容所有函数签名,有方法体。
从外部看不到实现的签名。在编写重载函数时,你应该始终在函数实现之上有两个或多个签名。
实现签名还必须与重载签名兼容。
例如,下面这个例子,就是实现签名与重载签名在函数参数类型不兼容。

function fn(x: boolean): void;
function fn(x: string): void;//error此重载签名与其实现签名不兼容
function fn(x: boolean) {}

稍微改动一下实现签名的函数参数即可:

function fn(x: boolean | string) {}

下面这个例子是实现签名与重载签名在返回值类型部分不兼容。

function fn(x: string): string;
function fn(x: number): boolean;
function fn(x: string | number) {
  return "oops";
}

同样,改动一下实现签名的返回值类型即可:

function fn(x: string | number): string | boolean {
  return 'oops'
}

需要注意的是,上面的改动,能使函数正常调用,但是函数调用的时候,不能传递一个不确定类型的值。例如,fn(Math.random() > 0.5 ? 'dfs' : true)
这将会导致报错,原因:TypeScript只会将函数调用解析为一种重载。传递可能值,会混淆TypeScript的判读。

编写好的重载

尽可能使用联合类型的参数而不是重载。
下面是一个返回字符串或数组长度的函数。

function len(s: string): number
function len(arr: any[]): number
function len(x: any) {
  return x.length
}
len('')
len([0])
len(Math.random() > 0.5 ? 'hello' : [0]) //error没有与此调用匹配的重载。

我们不能使用可能是字符串或数组的值来调用函数重载,因为TypeScript只能将函数调用解析为单个重载。
我们将函数改为非重载版本即可。

function len(x: any[] | string) {
  return x.length;
}

在函数中声明this

TypeScript 将通过代码流分析推断函数中的 this 应该是什么。

interface DB {
  filterUsers(filter: (this: User) => boolean): User[];
}
 
const db = getDB();
const admins = db.filterUsers(function (this: User) {
  return this.admin;
});

这种模式在回调风格的 API 中很常见,其中另一个对象通常控制何时调用你的函数。
请注意,你需要使用 function 而不是箭头函数来获得此行为。

其他需要了解的类型

void

void 表示不返回值的函数的返回值。只要函数没有任何 return 语句,或者没有从这些返回语句返回任何显式值,它就是推断类型。

function test1() {
  return
} //function test1(): void

function test2() {
  console.log('')
} //function test2(): void

在 JavaScript 中,不返回任何值的函数将隐式返回值 undefined。但是,void 和 undefined 在 TypeScript 中不是一回事。

object

特殊类型 object 指的是任何非基础值(string、number、bigint、boolean、symbol、null 或 undefined)。
object和{}不同。
object和Object也不同,在TypeScript中,你可能永远用不到Object。
在JavaScript中,函数值是对象:它们有属性,在它们的原型链中有 Object.prototype,是 instanceof Object,你可以在它们上调用 Object.keys,等等。
在 TypeScript 中,函数类型被视为 object。

unknown

unknown类型代表任何值,作用类似于any类型,但是比any类型安全,因为使用unknown做任何事情都是不合法的。
在这里插入图片描述
你可以描述一个返回未知类型值的函数,而不需要使用any。

function safeParse(s: string): unknown {
  return JSON.parse(s)
}

never

有些函数从不返回值,可以使用never定义返回值类型。

function fail(msg: string): never {
  throw new Error(msg)
}

never 类型表示从未观察到的值。在返回类型中,这意味着函数抛出异常或终止程序的执行
TypeScript确定联合中没有任何类型时,也会返回never。

function fail(msg: string): never {
  throw new Error(msg)
}
function fn(x: string | number) {
  if (typeof x === 'string') {
    console.log(x) //(parameter) x: string
  } else if (typeof x === 'number') {
    console.log(x) // (parameter) x: number
  } else {
    console.log(x) // (parameter) x: never
  }
}

Function

全局类型 Function 描述了 bind、call、apply 等属性,以及 JavaScript 中所有函数值上的其他属性。
它还具有 Function 类型的值始终可以被调用的特殊属性;这些调用返回 any。

function test(f: Function): void {
  const x = f(1, 2, 3) //const x: any
}

这是不安全的,如果函数可以接收任何类型的参数,且不需要返回值,那么建议用()=>void替换Function。

剩余形参和实参

剩余形参

除了使用可选参数或重载来制作可以接受各种固定参数计数的函数之外,我们还可以使用剩余参数定义接受无限数量参数的函数。
剩余参数出现在所有其他参数之后,并使用 … 语法
让我们来分析下面这段代码。其中m就是10,n就是1,2,3,4组成的数组。
返回值:n的所有数乘以m再返回一个数组,最终结果为:[10,20,30,40]

function multiply(m: number, ...n: number[]) {
  return n.map((item) => item * m)
}
const a = multiply(10, 1, 2, 3, 4)

剩余实参

相反,我们可以使用扩展语法从可迭代对象(例如数组)中提供可变数量的参数。例如,数组的 push 方法接受任意数量的参数:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2);

TypeScript 并不假定数组是不可变的。
下面这段代码就会报错,atan2是一个只接收两个参数的函数,TypeScript认为args是可变的,故TypeScript不允许将一个可变的数组传递给一个只能接收两个参数的函数。

const args = [8, 5]
const angle = Math.atan2(...args)

这种情况使用as const就可以解决了。

const args = [8, 5] as const
const angle = Math.atan2(...args)

参数解构

你可以使用参数解构来方便地将作为参数提供的对象解包到函数体中的一个或多个局部变量中。
和JavaScript中的解构差不多,就是多了类型的定义。

type ABC = { a: number; b: number; c: number }
function sum({ a, b, c }: ABC) {
  console.log(a + b + c)
}
sum({ a: 1, b: 2, c: 3 })

函数的可赋值性

返回类型void

具有 void 返回类型 (type voidFunc = () => void) 的上下文函数类型,当实现时,可以返回任何其他值,但会被忽略。
因此,下列写法是有效的。

type voidFunc = () => void

const f1: voidFunc = () => {
  return true
}
const f2: voidFunc = () => true
const f3: voidFunc = function () {
  return true
}
const v1 = f1();//const v1: void
const v2 = f2();//const v1 = f1()
const v3 = f3();//const v1 = f1()

我们可以发现,尽管TypeScript允许我们在函数类型的返回类型为void的情况下返回其他值,但是我们返回的值是不生效的。

当字面量函数定义具有 void 返回类型时,该函数不得返回任何内容。

function f2(): void {
  return true //不能将类型“boolean”分配给类型“void”
}

const f3 = function (): void {
  return true //不能将类型“boolean”分配给类型“void”
}

注意,这里的void是我们手动加在函数上的,是函数的返回类型。上面的voidFunc,是我们定义的某种函数的类型。
上面是直接定义整个函数的类型,下面定义的是函数的返回值类型。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu20.04下PCL安装,查看,卸载等操作

Ubuntu20.04下PCL安装&#xff0c;查看&#xff0c;卸载等操作 项目来源 https://github.com/PointCloudLibrary/pclhttps://pointclouds.org/documentation/modules.htmlhttps://pcl.readthedocs.io/projects/tutorials/en/master/ 点云学习&#xff1a; https://github.c…

Day57-Nginx反向代理与负载均衡初步应用

Day57-Nginx反向代理与负载均衡初步应用 1. Nginx代理介绍2. Nginx代理常见模式2.1 正向代理2.2 反向代理2.3 正向与反向代理区别 3. Nginx代理支持协议4. Nginx反向代理场景实践5. lb01安装部署nginx 1. Nginx代理介绍 1&#xff09;在没有代理的情况下&#xff0c;都是客户端…

苹果与百度合作,将在iPhone 16中使用生成式AI

3月25日&#xff0c;《科创板日报》消息&#xff0c;苹果将与百度进行技术合作&#xff0c;为今年即将发布的iPhone16、Mac系统和iOS 18提供生成式AI&#xff08;AIGC&#xff09;功能。 据悉&#xff0c;苹果曾与阿里巴巴以及另外一家国产大模型厂商进行了技术合作洽谈。最终…

信号处理--基于混合CNN和transfomer自注意力的多通道脑电信号的情绪分类的简单应用

目录 关于 工具 数据集 数据集简述 方法实现 数据读取 ​编辑数据预处理 传统机器学习模型(逻辑回归&#xff0c;支持向量机&#xff0c;随机森林) 多层感知机模型 CNNtransfomer模型 代码获取 关于 本实验利用结合了卷积神经网络 (CNN) 和 Transformer 组件的混合…

Qt 作业 24/3/26

1、实现闹钟 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime> #include <QLineEdit>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent …

FPGA之状态机学习

作为一名逻辑工程师&#xff0c;掌握和应用状态机设计是必不可少的。能够灵活的应用状态机是对逻辑工程师最基本的要求&#xff0c;状态机设计的好坏能够直接影响到设计系统的稳定性&#xff0c;所以学会状态机是非常的重要。 1.状态机的概念 状态机通过不同的状态迁移来完成特…

STM32之HAL开发——串口配置(源码)

串口收发原理框图&#xff08;F1系列&#xff09; 注意&#xff1a;数据寄存器有俩个一个是收一个是发&#xff0c;但是在标准库或者HAL库中没有特别区分开来是俩个寄存器&#xff01; USART 初始化结构体详解 HAL 库函数对每个外设都建立了一个初始化结构体&#xff0c;比如 …

如何快速在ESXi中嵌套部署一台ESXi服务器?

正文共&#xff1a;1234 字 26 图&#xff0c;预估阅读时间&#xff1a;2 分钟 我们之前介绍过VMWare ESXi服务器镜像的定制&#xff08;VMware ESXi部署镜像定制&#xff09;和部署&#xff08;惠普VMware ESXI 6.7定制版部署&#xff09;&#xff0c;但是还没有介绍过ESXi版本…

YOLOv8改进 | 主干篇 | 修复官方去除掉PP-HGNetV2的通道缩放功能(轻量又涨点,全网独家整理)

一、本文介绍 本文给大家带来的改进机制是大家在跑RT-DETR提供的HGNetV2时的一个通道缩放功能&#xff08;官方在前几个版本去除掉的一个功能&#xff09;&#xff0c;其中HGNetV2当我们将其集成在YOLOv8n的模型上作为特征提取主干的时候参数量仅为230W 计算量为6.7GFLOPs该网…

【机器学习之---数学】随机游走

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 随机游走 1. 概念 1.1 例1 在你的饮食俱乐部度过了一个富有成效的晚上后&#xff0c;你在不太清醒的状态下离开了。因此&#xff0c;你会醉醺醺地在展…

【opencv】实时位姿估计(real_time_pose_estimation)—3D模型注册

相机成像原理图 物体网格、关键点&#xff08;局内点、局外点&#xff09;图像 box.ply resized_IMG_3875.JPG 主程序main_registration.cpp 主要实现了利用OpenCV库进行3D模型的注册。主要步骤包括加载3D网格模型、使用鼠标事件选择对应的3D点进行2D到3D的注册、利用solvePnP算…

在django中使用kindeditor出现转圈问题

在django中使用kindeditor出现转圈问题 【一】基础检查 【1】前端检查 确保修改了uploadJson的默认地址 该地址需要在路由层有映射关系 确认有加载官方文件 kindeditor-all-min.js确保有传递csrfmiddlewaretoken 或者后端关闭了csrf验证 <textarea name"content&qu…

无人驾驶矿卡整体解决方案(5g物联网通信方案)

​无人驾驶矿卡是智能矿山的重要组成部分,通过远程操控替代人工驾驶,可以显著提高采矿效率和作业安全性。但要实现无人驾驶矿卡,需要依赖于可靠高效的通信网络,来传输现场视频、控制指令和运行数据。以下是某大型煤矿在部署无人驾驶矿卡时,所采用的星创易联物联网整体解决方案。…

如何区分模型文件是稳定扩散模型和LORA模型

区分模型文件是否为稳定扩散模型&#xff08;Stable Diffusion Models&#xff09;或LORA模型&#xff08;LowRank Adaptation&#xff09;通常需要对模型的结构和内容有一定的了解。以下是一些方法来区分这两种模型文件&#xff1a; 1. 文件格式和结构 稳定扩散模型&#xff1…

词根词缀基础

一&#xff0e;词根词缀方法&#xff1a; 1. 类似中文的偏旁部首&#xff08;比如“休”单人旁木→一个人靠木头上休息&#xff09; 2. 把单词拆分后&#xff0c;每一个部分都有它自己的意思&#xff0c;拼凑在一起就构成了这个单词的意思 3. 一个规律&#xff0c;适用大部分…

基于nodejs+vue多媒体素材管理系统python-flask-django-php

该系统采用了nodejs技术、express 框架&#xff0c;连接MySQL数据库&#xff0c;具有较高的信息传输速率与较强的数据处理能力。包含管理员、教师和用户三个层级的用户角色&#xff0c;系统管理员可以对个人中心、用户管理、教师管理、资源类型管理、资源信息管理、素材类型管理…

论文阅读-《Lite Pose: Efficient Architecture Design for 2D Human Pose Estimation》

摘要 这篇论文主要研究了2D人体姿态估计的高效架构设计。姿态估计在以人为中心的视觉应用中发挥着关键作用&#xff0c;但由于基于HRNet的先进姿态估计模型计算成本高昂&#xff08;每帧超过150 GMACs&#xff09;&#xff0c;难以在资源受限的边缘设备上部署。因此&#xff0…

(三)Ribbon负载均衡

1.1.负载均衡原理 SpringCloud底层其实是利用了一个名为Ribbon的组件&#xff0c;来实现负载均衡功能的。 1.2.源码跟踪 为什么我们只输入了service名称就可以访问了呢&#xff1f;之前还要获取ip和端口。 显然有人帮我们根据service名称&#xff0c;获取到了服务实例的ip和…

GitLab更新失败(Ubuntu)

在Ubuntu下使用apt更新gitlab报错如下&#xff1a; An error occurred during the signature verification.The repository is not updated and the previous index files will be used.GPG error: ... Failed to fetch https://packages.gitlab.com/gitlab/gitlab-ee/ubuntu/d…

Leetcode 3.26

Leetcode Hot 100 一级目录1.每日温度 堆1.数组中的第K个最大元素知识点&#xff1a;排序复杂度知识点&#xff1a;堆的实现 2.前 K 个高频元素知识点&#xff1a;优先队列 一级目录 1.每日温度 每日温度 思路是维护一个递减栈&#xff0c;存储的是当前元素的位置。 遍历整个…