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

ts相关笔记(基础必看)

推荐一下小册 TypeScript 全面进阶指南,此篇笔记来源于此,记录总结,加深印象!

另外,如果想了解更多ts相关知识,可以参考我的其他笔记:

  • vue3+ts开发干货笔记
  • TSConfig 配置(tsconfig.json)
  • ts相关笔记(Partial、Required、Readonly、Record、Exclude、Extract)
  • ts相关笔记(类型层级)
  • ts相关笔记(extends、infer、Pick、Omit)

原始类型和对象类型

原始类型

除了最常见的 number / string / boolean / null / undefined, ES6、ES11)又分别引入了 2 个新的原始类型:symbol 与 bigint

const name: string = 'ts';
const age: number = 18;
const male: boolean = false;
const undef: undefined = undefined;
const nul: null = null;
const obj: object = { name, age, male };
const bigintVar1: bigint = 90071992547409212n;
const bigintVar2: bigint = BigInt(9007199254740991);
const symbolVar: symbol = Symbol('unique');

null和undefined

  • 在js里,null表示一个空值,undefined表示没有值
  • 在ts里,null 与 undefined 类型都是有具体意义的类型

在没有开启strictNullChecks 检查的情况下,这两种类型会被视作其他类型的子类型,比如 string 类型会被认为包含了 null 与 undefined 类型:

const tmp1: null = null;
const tmp2: undefined = undefined;const tmp3: string = null; // 仅在关闭 strictNullChecks 时成立,下同
const tmp4: string = undefined;

void

用于描述一个内部没有 return 语句,或者没有显式 return 一个值的函数的返回值,如:

function func1() {}
function func2() {return;
}
function func3() {return undefined;
}

数组类型标注

const arr1: string[] = []; // 更推荐此写法const arr2: Array<string> = [];
元组(Tuple)

元组就是类型和数据的个数一开始就已经限定好了,某些情况下使用元组代替数组要更加妥当。
下面是一些应用

  • 提供越界提醒

    const arr3: string[] = ['aaa', 'bbb', 'ccc']
    const arr4: [string,string,string] = ['aaa', 'bbb', 'ccc']
    console.log(arr4[4])
    

    在这里插入图片描述

  • 可选

    const arr6: [string, number?, boolean?] = ['aaa'];
    // 下面这么写也可以
    // const arr6: [string, number?, boolean?] = ['aaa', , ,];
    
  • 具名元组
    在 TypeScript 4.0 中,有了具名元组(Labeled Tuple Elements)的支持,使得我们可以为元组中的元素打上类似属性的标记:

    const arr7: [name: string, age: number, male?: boolean] = ['aaa', 18, true];
    

对象类型标注

使用interface接口
interface IDescription {name: string;age: number;male: boolean;
}const obj1: IDescription = {name: 'aaa',age: 599,male: true,
};

可选 ?

interface IDescription {name: string;age: number;male?: boolean;func?: Function;
}const obj2: IDescription = {name: 'aaa',age: 599,male: true,// 无需实现 func 也是合法的
};

只读

interface IDescription {readonly name: string;age: number;
}const obj3: IDescription = {name: 'aaa',age: 599,
};// 无法分配到 "name" ,因为它是只读属性
obj3.name = "AAA";
使用type 类型别名
type User = {name: stringage: number
};

很多人更喜欢用 type(Type Alias,类型别名)来代替接口结构描述对象,
而更推荐的方式是

  • interface 用来描述对象、类的结构
  • type类型别名用来将一个函数签名、一组联合类型、一个工具类型等等抽离成一个完整独立的类型

但大部分场景下接口结构都可以被类型别名所取代,取决于个人喜好或者团队的一些规范吧。

object、Object 以及 { }

Object

js中,原型链的顶端是 Object 以及 Function,这也就意味着所有的原始类型与对象类型最终都指向 Object,在 TypeScript 中就表现为 Object 包含了所有的类型

// 对于 undefined、null、void 0 ,需要关闭 strictNullChecks
const tmp1: Object = undefined;
const tmp2: Object = null;
const tmp3: Object = void 0;const tmp4: Object = 'aaa';
const tmp5: Object = 599;
const tmp6: Object = { name: 'aaa' };
const tmp7: Object = () => {};
const tmp8: Object = [];

和 Object 类似的还有 Boolean、Number、String、Symbol,这几个装箱类型(Boxed Types) 同样包含了一些超出预期的类型。
以 String 为例,它同样包括 undefined、null、void,以及代表的 拆箱类型(Unboxed Types) —> string,但并不包括其他装箱类型对应的拆箱类型,如 boolean 与 基本对象类型,我们看以下的代码:

const tmp9: String = undefined;
const tmp10: String = null;
const tmp11: String = void 0;
const tmp12: String = 'aaa';// !!!  以下不成立,因为不是字符串类型的拆箱类型
const tmp13: String = 599; 
const tmp14: String = { name: 'aaa' }; 
const tmp15: String = () => {}; 
const tmp16: String = []; 

object
object 的引入就是为了解决对 Object 类型的错误使用,它代表所有非原始类型的类型,即数组、对象与函数类型这些:

const tmp17: object = undefined;
const tmp18: object = null;
const tmp19: object = void 0;const tmp20: object = 'aaa';  // X 不成立,值为原始类型
const tmp21: object = 599; // X 不成立,值为原始类型const tmp22: object = { name: 'aaa' };
const tmp23: object = () => {};
const tmp24: object = [];

{ }
可以认为使用{ }作为类型签名就是一个合法的,但内部无属性定义的空对象,
这类似于 Object(想想 new Object()),它意味着任何非 null / undefined 的值:

const tmp25: {} = undefined; // 仅在关闭 strictNullChecks 时成立,下同
const tmp26: {} = null;
const tmp27: {} = void 0; // void 0 等价于 undefinedconst tmp28: {} = 'aaa';
const tmp29: {} = 599;
const tmp30: {} = { name: 'aaa' };
const tmp31: {} = () => {};
const tmp32: {} = [];

虽然能够将其作为变量的类型,但你实际上无法对这个变量进行任何赋值操作:

const tmp30: {} = { name: 'aaa' };tmp30.age = 18; // X 类型“{}”上不存在属性“age”。

总结

  • 在任何时候都不要,不要,不要使用 Object 以及类似的装箱类型。

  • 当你不确定某个变量的具体类型,但能确定它不是原始类型,可以使用
    object。但更推荐进一步区分,也就是使用
    Record<string, unknown> 或 Record<string, any> 表示对象,
    unknown[] 或 any[] 表示数组,
    (…args: any[]) => any表示函数 这样。

  • 我们同样要避免使用{}。{}意味着任何非 null / undefined 的值,从这个层面上看,使用它和使用 any 一样恶劣。

字面量类型和枚举

字面量类型

看一个例子,我们开发中定义的请求 接口返回 结果可能如下

interface Res {code: 10000 | 10001 | 50000;status: "success" | "failure";data: any;
}

上面"success" 或者 “failure” 不是一个值吗?为什么它也可以作为类型?

在 TypeScript 中,这叫做字面量类型(Literal Types),它代表着比原始类型更精确的类型,同时也是原始类型的子类型

字面量类型主要包括:字符串字面量类型、数字字面量类型、布尔字面量类型和对象字面量类型,它们可以直接作为类型标注:

const str: "aaa" = "aaa";
const num: 599 = 599;
const bool: true = true
// 报错!Type '"aaa123"' is not assignable to type '"aaa"'
const str1: "aaa" = "aaa123";

单独使用字面量类型比较少见,因为单个字面量类型并没有什么实际意义。
它通常和联合类型(即这里的 |)一起使用,表达一组字面量类型:

interface Tmp {bool: true | false;num: 1 | 2 | 3;str: "aa" | "bb" | "cc"
}

补充:联合类型

联合类型你可以理解为,它代表了一组类型的可用集合,只要最终赋值的类型属于联合类型的成员之一,就可以认为符合这个联合类型。
联合类型对其成员并没有任何限制,除了上面这样对同一类型字面量的联合,我们还可以将各种类型混合到一起:

interface Tmp {mixed: true | string | 599 | {} | (() => {}) | (1 | 2)
}

联合类型的常用场景之一是通过多个对象类型的联合,来实现手动的互斥属性,即这一属性如果有字段1,那就没有字段2:

interface Tmp {user:| {vip: true;expires: string;}| {vip: false;promotion: string;};
}declare var tmp: Tmp;if (tmp.user.vip) {console.log(tmp.user.expires);
}
枚举
// js中定义一些常量
export const PageUrl = {Home_Page_Url: "url1",Setting_Page_Url: "url2",Share_Page_Url: "url3",
}

使用ts的枚举 enum

enum PageUrl {Home_Page_Url = "url1",Setting_Page_Url = "url2",Share_Page_Url = "url3",
}
// 使用
const home = PageUrl.Home_Page_Url;

如果你没有声明枚举的值,它会默认使用数字枚举,并且从 0 开始,以 1 递增:

enum Items {Foo,Bar,Baz
}
// Items.Foo , Items.Bar , Items.Baz的值依次是 0,1,2 

如果你只为某一个成员指定了枚举值,那么之前未赋值成员仍然会使用从 0 递增的方式,之后的成员则会开始从枚举值递增。

enum Items {Foo,  // 0 Bar = 599,Baz // 600
}

枚举和对象的重要差异在于,对象是单向映射的,我们只能从键映射到键值。
而枚举是双向映射的,即你可以从枚举成员映射到枚举值,也可以从枚举值映射到枚举成员:

enum Items {Foo,Bar,Baz
}const fooValue = Items.Foo; // 0
const fooKey = Items[0]; // "Foo"

函数和class中的类型

函数
// 函数声明
function foo(name: string): number {return name.length;
}
// 函数表达式const foo = function (name: string): number {return name.length
}
const foo: (name: string) => number = function (name) {return name.length
}// 箭头函数
// 方式一
const foo = (name: string): number => {return name.length
}// 方式二 代码的可读性会非常差,不推荐
const foo: (name: string) => number = (name) => {return name.length
}

要么直接在函数中进行参数和返回值的类型声明,要么使用类型别名将函数声明抽离出来,如下:

type FuncFoo = (name: string) => numberconst foo: FuncFoo = (name) => {return name.length
}

如果只是为了描述这个函数的类型结构,我们甚至可以使用 interface 来进行函数声明:

interface FuncFooStruct {(name: string): number
}

void 类型

// 没有调用 return 语句
function foo(): void { }// 调用了 return 语句,但没有返回值
function bar(): void {return;
}

可选参数与 rest 参数

使用 ? 描述一个可选参数
注意:可选参数必须位于必选参数之后

// 在函数逻辑中注入可选参数默认值
function foo1(name: string, age?: number): number {const inputAge = age || 18; // 或使用 age ?? 18return name.length + inputAge
}// 直接为可选参数声明默认值
function foo2(name: string, age: number = 18): number {const inputAge = age;return name.length + inputAge
}

对于 rest 参数的类型标注也比较简单,由于其实际上是一个数组,这里我们也应当使用数组类型进行标注:

function foo(arg1: string, ...rest: any[]) { }// 元组标注
function foo(arg1: string, ...rest: [number, boolean]) { }foo("aaa", 18, true)

重载
在某些逻辑较复杂的情况下,函数可能有多组入参类型和返回值类型:

function func(foo: number, bar?: boolean): string | number {if (bar) {return String(foo);} else {return foo * 599;}
}

要想实现与入参关联的返回值类型,我们可以使用 TypeScript 提供的函数重载签名(Overload Signature),将以上的例子使用重载改写:

function func(foo: number, bar: true): string;
function func(foo: number, bar?: false): number;
function func(foo: number, bar?: boolean): string | number {if (bar) {return String(foo);} else {return foo * 599;}
}const res1 = func(599); // number
const res2 = func(599, true); // string
const res3 = func(599, false); // number

异步函数

async function asyncFunc(): Promise<void> {}

对于异步函数(即标记为 async 的函数),其返回值必定为一个 Promise 类型,而 Promise 内部包含的类型则通过泛型的形式书写,即 Promise < T >

class

一个函数的主要结构即是参数、逻辑和返回值,对于逻辑的类型标注其实就是对普通代码的标注,所以我们只介绍了对参数以及返回值的类型标注。

而到了 Class 中其实也一样,它的主要结构只有构造函数、属性、方法和访问符(Accessor),我们也只需要关注这三个部分即可

构造函数

class Foo {prop: string;constructor(inputProp: string) {this.prop = inputProp;}print(addon: string): void {console.log(`${this.prop} and ${addon}`)}get propA(): string {return `${this.prop}+A`;}set propA(value: string) {this.prop = `${value}+A`}
}

!!setter 方法不允许进行返回值的类型标注,你可以理解为 setter 的返回值并不会被消费,它是一个只关注过程的函数。

修饰符
分别有 public / private / protected / readonly
readonly 属于操作性修饰符(就和 interface 中的 readonly 意义一致)
其它三个属于访问性修饰符

  • public:此类成员在类、类的实例、子类中都能被访问。
  • private:此类成员仅能在类的内部被访问。
  • protected:此类成员仅能在类与子类中被访问,你可以将类和类的实例当成两种概念,即一旦实例化完毕(出厂零件),那就和类(工厂)没关系了,即不允许再访问受保护的成员。
class Foo {private prop: string;constructor(inputProp: string) {this.prop = inputProp;}protected print(addon: string): void {console.log(`${this.prop} and ${addon}`)}public get propA(): string {return `${this.prop}+A`;}public set propA(value: string) {this.propA = `${value}+A`}
}

抽象类
抽象类是对类结构与方法的抽象,简单来说,一个抽象类描述了一个类中应当有哪些成员(属性、方法等),一个抽象方法描述了这一方法在实际实现中的结构。

abstract class AbsFoo {abstract absProp: string;abstract get absGetter(): string;abstract absMethod(name: string): string
}

抽象类中的成员也需要使用 abstract 关键字才能被视为抽象类成员,如这里的抽象方法。我们可以实现(implements)一个抽象类:

class Foo implements AbsFoo {absProp: string = "aaa"get absGetter() {return "aaa"}absMethod(name: string) {return name}
}

另外使用 interface 不仅可以声明函数结构,也可以声明类的结构:

interface FooStruct {absProp: string;get absGetter(): string;absMethod(input: string): string
}class Foo implements FooStruct {absProp: string = "aaa"get absGetter() {return "aaa"}absMethod(name: string) {return name}
}

any、unknown、never

any 类型的主要意义,其实就是为了表示一个无拘无束的“任意类型”,它能兼容所有类型,也能够被所有类型兼容。

千万不要 anyscript !!!

unknown 类型的变量可以再次赋值为任意其它类型,但只能赋值给 any 与 unknown 类型的变量

let unknownVar: unknown = "aaa";unknownVar = false;
unknownVar = "aaa";
unknownVar = {site: "bbb"
};unknownVar = () => { }const val1: string = unknownVar; // Error
const val2: number = unknownVar; // Error
const val3: () => {} = unknownVar; // Error
const val4: {} = unknownVar; // Errorconst val5: any = unknownVar;
const val6: unknown = unknownVar;

any 放弃了所有的类型检查,而 unknown 并没有

let unknownVar: unknown;unknownVar.foo(); // 报错:对象类型为 unknown
// 类型断言
let unknownVar: unknown;(unknownVar as { foo: () => {} }).foo();

类型断言: 虽然这是一个未知的类型,但我跟你保证它在这里就是这个类型!

never 类型被称为 Bottom Type,是整个类型系统层级中最底层的类型

never 类型不携带任何的类型信息,因此会在联合类型中被直接移除
在这里插入图片描述

泛型

可以理解为一个接受参数的函数

类型别名type中的泛型

type Factory<T> = T | number | string;

type中的泛型大多是用来进行工具类型封装,比如

// 把一个对象中的所有属性变成 string类型
type Stringify<T> = {[K in keyof T]: string;
};// 复制对象中的所有属性类型
type Clone<T> = {[K in keyof T]: T[K];
};

看一个例子

type Partial<T> = {[P in keyof T]?: T[P];
};
interface IFoo {prop1: string;prop2: number;prop3: boolean;prop4: () => void;
}type PartialIFoo = Partial<IFoo>;// 等价于
interface PartialIFoo {prop1?: string;prop2?: number;prop3?: boolean;prop4?: () => void;
}

泛型还可以作为条件类型中的判断条件

type IsEqual<T> = T extends true ? 1 : 2;type A = IsEqual<true>; // 1
type B = IsEqual<false>; // 2
type C = IsEqual<'linbudu'>; // 2

可以设置默认值

  • List item
type Factory<T = boolean> = T | number | string;// 调用时就可以不带任何参数了,默认会使用我们声明的默认值来填充
const foo: Factory = false;

可以使用 extends 关键字来约束传入的泛型参数必须符合要求
比如:

  • A extends B 意味着 A 是 B 的子类型
  • ‘aaa’ extends string,18 extends number 成立。
  • 联合类型子集均为联合类型的子类型,即 1、 1 | 2 是 1 | 2 | 3 | 4 的子类型
  • { name: string } 是 {} 的子类型,因为在 {} 的基础上增加了额外的类型

看下面例子,根据传入的请求码判断请求是否成功

type ResStatus<ResCode extends number> = ResCode extends 10000 | 10001 | 10002? 'success': 'failure';type Res1 = ResStatus<10000>; // "success"
type Res2 = ResStatus<20000>; // "failure"type Res3 = ResStatus<'10000'>; // 类型“string”不满足约束“number”。
type ResStatus<ResCode extends number = 10000> = ResCode extends 10000 | 10001 | 10002? 'success': 'failure';type Res4 = ResStatus; // "success"

多泛型关联
不仅可以同时传入多个泛型参数,还可以让这几个泛型参数之间也存在联系,类似于传入多个参数

type Conditional<Type, Condition, TruthyResult, FalsyResult> =Type extends Condition ? TruthyResult : FalsyResult;//  "passed!"
type Result1 = Conditional<'aaa', string, 'passed!', 'rejected!'>;// "rejected!"
type Result2 = Conditional<'bbb', boolean, 'passed!', 'rejected!'>;

接口interface中的泛型

常见的一个例子应该还是响应类型结构的泛型处理:

interface IRes<TData = unknown> {code: number;error?: string;data: TData;
}

这个接口描述了一个通用的响应类型结构,预留出了实际响应数据的泛型坑位,然后在你的请求函数中就可以传入特定的响应类型了:

interface IUserProfileRes {name: string;homepage: string;avatar: string;
}function fetchUserProfile(): Promise<IRes<IUserProfileRes>> {}type StatusSucceed = boolean;
function handleOperation(): Promise<IRes<StatusSucceed>> {}

函数中的泛型

函数中的泛型是很常用的,主要是做:类型的自动提取

function handle<T>(input: T): T {}

我们为函数声明了一个泛型参数 T,并将参数的类型与返回值类型指向这个泛型参数。这样,在这个函数接收到参数时,T 会自动地被填充为这个参数的类型。

例子:

function handle<T>(input: T): T {}const author = "aaa"; // 使用 const 声明,被推导为 "aaa"let authorAge = 18; // 使用 let 声明,被推导为 numberhandle(author); // 填充为字面量类型 "aaa"
handle(authorAge); // 填充为基础类型 number

在基于参数类型进行填充泛型时,其类型信息会被推断到尽可能精确的程度,如这里会推导到字面量类型而不是基础类型。
这是因为在直接传入一个值时,这个值是不会再被修改的,因此可以推导到最精确的程度。而如果你使用一个变量作为参数,那么只会使用这个变量标注的类型(在没有标注时,会使用推导出的类型)。

例子:

function swap<T, U>([start, end]: [T, U]): [U, T] {return [end, start];
}const swapped1 = swap(["aaa", 18]); // const swapped1: [number, string]
const swapped2 = swap([null, 18]); // const swapped2: [number, null]
const swapped3 = swap([{ name: "aaa" }, {}]); // const swapped3: [{}, { name: string;}]

函数中的泛型同样存在约束与默认值

// 不再处理对象类型的情况了
function handle<T extends string | number>(input: T): T {}
// 只想处理数字元组的情况
function swap<T extends number, U extends number>([start, end]: [T, U]): [U, T] {return [end, start];
}

函数的泛型参数也会被内部的逻辑消费,如:

function handle<T>(payload: T): Promise<[T]> {return new Promise<[T]>((res, rej) => {res([payload]);});

对于箭头函数的泛型,其书写方式是这样的:

const handle = <T>(input: T): T => {}

在 tsx 文件中泛型的尖括号可能会造成报错,编译器无法识别这是一个组件还是一个泛型,此时你可以让它长得更像泛型一些:

const handle = <T extends any>(input: T): T => {}

需要注意的是,不要为了用泛型而用泛型,就像这样:
没有意义

function handle<T>(arg: T): void {console.log(arg);
};

Class 中的泛型

Class 中的泛型和函数中的泛型非常类似,只不过函数中泛型参数的消费方是参数和返回值类型
Class 中的泛型消费方则是属性、方法、乃至装饰器等。
同时 Class 内的方法还可以再声明自己独有的泛型参数。我们直接来看完整的示例:

class Queue<TElementType> {private _list: TElementType[];constructor(initial: TElementType[]) {this._list = initial;}// 入队一个队列泛型子类型的元素enqueue<TType extends TElementType>(ele: TType): TElementType[] {this._list.push(ele);return this._list;}// 入队一个任意类型元素(无需为队列泛型子类型)enqueueWithUnknownType<TType>(element: TType): (TElementType | TType)[] {return [...this._list, element];}// 出队dequeue(): TElementType[] {this._list.shift();return this._list;}
}

相关文章:

ts相关笔记(基础必看)

推荐一下小册 TypeScript 全面进阶指南&#xff0c;此篇笔记来源于此&#xff0c;记录总结&#xff0c;加深印象&#xff01; 另外&#xff0c;如果想了解更多ts相关知识&#xff0c;可以参考我的其他笔记&#xff1a; vue3ts开发干货笔记TSConfig 配置&#xff08;tsconfig.…...

Docker随笔

OverView 为什么需要Docker 如果我需要部署一个服务&#xff0c;那么我需要提前部署其他应用栈&#xff0c;不同的应用栈会依赖于不用的操作系统和环境。这样做会产生一些负面影响&#xff1a; 不同版本依赖较长的部署时间不同的Dev/Test/Prod环境 这时我们需要一个工具去解…...

uni-app 前后端调用实例 基于Springboot

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…...

vue3+ts开发干货笔记

总结一下在vue3中ts的使用。当篇记录部分来自于vue官网&#xff0c;记录一下&#xff0c;算是加深印象吧。 纯干笔记&#xff0c;不断补充&#xff0c;想到什么写什么&#xff0c;水平有限&#xff0c;欢迎评论指正&#xff01; 另外&#xff0c;如果想了解更多ts相关知识&…...

Android开发新的一年Flag

在新的一年里&#xff0c;为了提升Android开发技能&#xff0c;实现更优质的应用程序&#xff0c;我们制定了2024的新年Flag。这些Flag涵盖了技术学习、代码优化、架构升级、用户体验等多个方面&#xff0c;旨在帮助我们成为更优秀的Android开发者。 1. 学习新技术 1.1. Andr…...

好的OODA循环与快慢无关

OODA循环是指观察&#xff08;Observe&#xff09;、导向&#xff08;Orient&#xff09;、决策&#xff08;Decide&#xff09;和行动&#xff08;Act&#xff09;这四个步骤的循环过程。它是一种决策和行动的框架&#xff0c;旨在帮助个人或组织更快地适应和应对变化。 OODA循…...

Android 车联网——CarUserService介绍(十三)

一、简介 CarUserService 是 Android 汽车平台的一个组件,它用于管理和提供车辆用户信息。该组件可以让开发者创建和管理与车辆用户相关的数据和配置,包括车辆拥有者和乘客的个人信息、偏好设置、用户偏好配置文件等。 CarUserService 提供了以下功能和特性: 用户配置管理:…...

【开题报告】基于微信小程序的母婴商品仓库管理系统的设计与实现

1.选题背景 随着社会经济的发展和家庭生活水平的提高&#xff0c;母婴商品市场逐渐兴起。然而&#xff0c;传统的母婴商品仓库管理方式存在着许多问题&#xff0c;如信息不透明、操作繁琐等。为了提高仓库管理的效率和准确性&#xff0c;基于微信小程序的母婴商品仓库管理系统…...

分布式锁相关问题(三)

Redis实战精讲-13小时彻底学会Redis 一、什么是分布式锁&#xff1f; 要介绍分布式锁&#xff0c;首先要提到与分布式锁相对应的是线程锁、进程锁。 l 线程锁&#xff1a;主要用来给方法、代码块加锁。当某个方法或代码使用锁&#xff0c;在同一时刻仅有一个线程执行该方法或该…...

grep!Linux系统下强大的文本搜索工具!

grep&#xff01;Linux系统下强大的文本搜索工具&#xff01; grep是一个强大的文本搜索工具&#xff0c;它可以在文件中查找包含指定字符串的行。grep的基本语法如下&#xff1a; grep [选项] "搜索字符串" 文件名其中&#xff0c;选项可以是以下几种&#xff1a;…...

(学习打卡1)重学Java设计模式之设计模式介绍

前言&#xff1a;听说有本很牛的关于Java设计模式的书——重学Java设计模式&#xff0c;然后买了(*^▽^*) 开始跟着小傅哥学Java设计模式吧&#xff0c;本文主要记录笔者的学习笔记和心得。 打卡&#xff01;打卡&#xff01; 设计模式介绍 一、设计模式是什么&#xff1f; …...

docker 部署教学版本

文章目录 一、docker使用场景及常用命令1&#xff09;docker使用场景2&#xff09;rocky8(centos8)安装 docker3&#xff09;docker 常用命令补充常用命令 二、 单独部署每个镜像&#xff0c;部署spring 应用镜像推荐&#xff08;2023-12-18&#xff09;1、 安装使用 mysql1.1 …...

2023春季李宏毅机器学习笔记 05 :机器如何生成图像

资料 课程主页&#xff1a;https://speech.ee.ntu.edu.tw/~hylee/ml/2023-spring.phpGithub&#xff1a;https://github.com/Fafa-DL/Lhy_Machine_LearningB站课程&#xff1a;https://space.bilibili.com/253734135/channel/collectiondetail?sid2014800 一、图像生成常见模型…...

C#和C++存储 和 解析 bin 文件

C 解析 bin 文件 // C 解析 bin 文件 #include <stdio.h>int main() {FILE *file; // 定义文件指针file fopen("example.bin", "rb"); // 打开二进制文件&#xff08;只读模式&#xff09;if (file NULL) {printf("无法打开文件\n");re…...

【React系列】Redux(二)中间件

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 中间件的使用 1.1. 组件中异步请求 在之前简单的案例中&#xff0c;redux中保存的counter是一个本地定义的数据…...

YOLOv8改进 | 2023Neck篇 | 利用Gold-YOLO改进YOLOv8对小目标检测

一、本文介绍 本文给大家带来的改进机制是Gold-YOLO利用其Neck改进v8的Neck,GoLd-YOLO引入了一种新的机制——信息聚集-分发(Gather-and-Distribute, GD)。这个机制通过全局融合不同层次的特征并将融合后的全局信息注入到各个层级中,从而实现更高效的信息交互和融合。这种…...

ubuntu环境安装配置nginx流程

今天分享ubuntu环境安装配置nginx流程 一、下载安装 1、检查是否已经安装 nginx -v 结果 2、安装 apt install nginx-core 过程 查看版本&#xff1a;nginx -v 安装路径&#xff1a;whereis nginx nginx文件安装完成之后的文件位置&#xff1a; /usr/sbin/nginx&#xf…...

【LMM 010】MiniGPT-v2:使用独特的标识符实现视觉语言多任务学习的统一的多模态大模型

论文标题&#xff1a;MiniGPT-v2: Large Language Model As a Unified Interface for Vision-Language Multi-task Learning 论文作者&#xff1a;Jun Chen, Deyao Zhu, Xiaoqian Shen, Xiang Li, Zechun Liu, Pengchuan Zhang, Raghuraman Krishnamoorthi, Vikas Chandra, Yun…...

人工智能如何重塑金融服务业

在体验优先的世界中识别金融服务业中的AI使用场景 人工智能&#xff08;AI&#xff09;作为主要行业的大型组织的重要业务驱动力&#xff0c;持续受到关注。众所周知&#xff0c;传统金融服务业在采用新技术方面相对滞后&#xff0c;一些组织使用的还是上世纪50年代和60年代发…...

Iterable 对象转换为 Stream 对象

在 Java 8 中&#xff0c;可以使用 Stream API 来对集合进行操作。要将 Iterable 对象转换为 Stream 对象&#xff0c;可以使用 StreamSupport 类的 stream() 方法。具体来说&#xff0c;可以按照以下步骤进行转换&#xff1a; 调用 Spliterators.spliteratorUnknownSize(iter…...

基于Java+SpringBoot+vue+elementUI私人健身教练预约管理系统设计实现

基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录 基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现一、前言介绍&#xff1a;二、系统设计&#xff1a;2.1 性能需求分析2.2 B/S架构&…...

2024,启动(回顾我的2023)

零.前言 打开博客想写个年度总结&#xff0c;发现已经半年没有更新文章了&#xff0c;排名从几千掉到了几万&#xff0c;不过数据量还是不错的。 时间过得可真快&#xff0c;2023年是充满动荡的一年&#xff0c;上半年gpt横空出世&#xff0c;下半年各种翻车暴雷吃瓜吃到嘴软…...

Web网页开发-盒模型-笔记

1.CSS的三种显示方式 (1)块级元素:标签所占区域默认为一行 特点&#xff1a;一行一个 可设宽高 (2)行内元素&#xff1a;标签所占区域由内容顶开&#xff0c;行内元素无法使用text-align 特点&#xff1a;一行多个 不可设宽高&#xff0c;margin上下和padding上下都不能改变位…...

Java打成压缩包的方法汇总

文章目录 1.将指定目录下的文件打包成 .zip2.将指定目录下的文件打包成 .tar.gz3.将指定目录下的文件打包成 .tar4.将指定目录下的文件打包成 .rar5.生成若干个txt并打包到zip中 1.将指定目录下的文件打包成 .zip 代码示例&#xff1a; import java.io.*; import java.util.z…...

2023年第2季社区Task挑战赛贡献者榜单

基于FISCO BCOS及Weldentity&#xff0c;实现SSO单点登录服务&#xff1b;提供食品溯源、电商运费险7天退保、电子病历等智能合约库业务场景案例&#xff1b;基于FISCO BCOS更新游戏体验&#xff1b;体验并分析解读最新发布的分布式数据协作管理解决方案DDCMS&#xff0c;提供相…...

Clickhouse 为什么快

ClickHouse是一个用于联机分析处理&#xff08;OLAP&#xff09;的开源列式数据库管理系统&#xff08;DBMS&#xff09;。它之所以能提供出色的查询性能和处理速度&#xff0c;主要归功于以下几个方面的设计和优化&#xff1a; 列式存储 ClickHouse存储数据按列而不是按行组织…...

【React系列】react-router

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 认识react-router 1.2. 前端路由原理 前端路由是如何做到URL和内容进行映射呢&#xff1f;监听URL的改变。 UR…...

[数据集][目标检测]车辆检测数据集VOC+YOLO格式1.6w张3类别

一共分为3个压缩包&#xff1a; 【车辆检测数据集AVOCYOLO格式5423张3类别】 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;5423 标注数…...

FindMy技术用于鼠标

鼠标是计算机的标准配置之一&#xff0c;其设计初衷是为了使计算机的操作更加简便快捷&#xff0c;减少用户在操作中的负担。用户可以通过移动鼠标&#xff0c;实现光标的精确移动&#xff0c;进而选择、拖拽、复制、粘贴等操作。这种操作方式&#xff0c;使得计算机的操作变得…...

已解决‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。”的问题

已解决‘ping‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。”的问题 文章目录 问题介绍 问题分析 解决思路 解决方法 检查并修复环境变量 进入c:\windows\system32再ping 使用系统工具修复系统文件 Q1 - 问题介绍 当您尝试在Windows命令提示符下…...

汕头模版网站建设/seo上海网站推广

舍与得 前言 凡是过往&#xff0c;皆为序章 规划自己就像玩游戏一样。要么氪金&#xff0c;要么爆肝&#xff0c;还有就是又氪又肝。规划有三个部分&#xff0c;首先是目标&#xff0c;确定目标&#xff0c;才能确定方向&#xff1b;第二是方法&#xff0c;方法正确&#xff0…...

做购物平台网站 民治/怎样推广小程序平台

这两天公司成立了go语言学习兴趣小组&#xff0c;慕名参与了学习。目前对于go是0基础&#xff0c;只知道它可以做高并发、效率快、编译简单、母语是C. go的安装有多种形式&#xff0c;编译安装是比较慢的一个&#xff0c;今天我就记录一下学习go编译安装流程。 1、下载软件包 h…...

企业做网站有发展么/中文搜索引擎有哪些平台

SQL Server数据库镜像的页面自动修复原理 主库页面损坏 镜像库页面损坏 LSN用来保证事务的时序 LSN保存在每个数据页面的页头 在同一台机器&#xff0c;内存中的数据页和磁盘中的数据页保持同步依靠的是数据页头的LSN和事务日志LDF文件里的LSN 当跨机器的时候&#xff0c;内存中…...

seo公司 彼亿营销/宁波优化网站哪家好

ubuntu下修改postgres数据库用户的密码为123456sudo -u postgres psqlpostgres# ALTER USER postgres WITH PASSWORD 123456;修改ubuntu操作系统的postgres用户的密码(密码要与数据库用户postgres的密码相同)sudo passwd –d postgressudo -u postgres passwdvi /etc/postgresq…...

西部数码网站管理助手/上海专业网络推广公司

1.执行whereis mysql会有如下打印&#xff1a;mysql: /usr/bin/mysql /usr/lib64/mysql /usr/include/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz2.cd /usr/share/mysql目录下查看存在mysql.server文件3.复制mysql.server文件 到 /etc/init.d/下&#xff0c;命名为…...

wordpress超简洁主题/跨境电商哪个平台比较好

在《【Hibernate】Hibernate的聚类查询、分组查询、排序与时间之差》&#xff08;点击打开链接&#xff09;一文中已经讲述过如何利用HQL语句取代SQL语句&#xff0c;进行聚类查询、分组查询、排序与时间之差的查询&#xff0c;同时指出hql能代替sql语句做任何事情。我原本以为…...