【TypeScript】入门基础知识

news2024/11/16 2:36:10

        目前在做项目的技术栈是 react+typescript,之前只知道 ts 是 js 的扩展,增加了类型检查,但是没有仔细的学过,纯纯看别人代码上手 anyscript(这很难评...)。趁着最近空闲,就学习一下 ts 的基础知识,此篇笔记只包含基础知识,内容并不深入,仅供熟悉 js 的 ts 新手参考。

一、搭建开发环境

        这边提供 tsc ts-node 两种方式:(1)tsc 是一个编译器,把 ts 编译为 js。只编译。(2)ts-node 是一个执行环境,把 ts 编译为 js ,然后在node上运行。即:编译+执行。

1、tsc 编译器

        (1)下载 Node.js 并安装(不详细赘述,百度就行)

        (2)使用 npm 全局安装 typescript:npm i -g typescript

        (3)检查 tsc 编译器是否安装成功:tsc -v

        如果出现版本号则安装成功;如果报错“tsc不是内部命令”,则需要添加环境变量,具体步骤参考:typeScript安装及TypeScript tsc 不是内部或外部命令,也不是可运行的程序或批处理文件解决办法_安装tsc(程序)-CSDN博客

        (4)创建一个 ts 文件并用 tsc 编译器进行编译,进入 ts 文件所在目录的命令行,执行命令:tsc xxx.ts

2、ts-node

        (1)下载 Node.js 并安装(不详细赘述,百度就行)

        (2)使用 npm 全局安装 typescript:npm i -g typescript

        (3)安装 ts-node:npm install -g ts-node

        (4)ts-node需要依赖 tslib 和 @types/node 两个包:npm install tslib @types/node -g 

        (4)创建一个 ts 文件 xxx.ts ,并执行命令:ts-node xxx.ts

二、类型

1、类型声明

  • 通过类型声明可以指定 ts 中变量(参数、形参)的类型
  • 类型声明给变量设置了类型,使得变量只能存储某种类型的值。指定类型后,当为变量赋值时,ts 编译器会自动检查值是否符合类型声明,符合则赋值,不符合则报错。
  • 语法
    let 变量: 类型
    
    let 变量: 类型 = 值
     
    function fn(参数: 类型, 参数: 类型): 类型 {
    }

 2、基本类型

2.1 数组类型 array

//====== 语法 ======
//(1)类型+方括号
let arr1: number[] = [1, 2, 3, 4, 5];

//(2)使用数组泛型 Array<elemType>
let arr2: Array<number> = [1, 2, 3, 4, 5];

2.2 对象类型 object

        对象有很多种类,{}是对象,函数也是对象,因此直接定义类型为 object 是没有意义的。于对象而言,我们希望能够指定它是“怎样”的对象,而非“它是对象”。

(1)基本用法

        赋值的时候,定义的变量与对象的属性必须完全一致,不能多也不能少。

let person: { name: string, age: number };
person = {
    name: 'Tom',
    age: 18,
}

(2)设置可选属性

// 1. 设置可选属性:sex属性可有可无
let person1: { name: string, age: number, sex?: string };
person1 = {
    name: 'Tom',
    age: 18,
    sex: 'male'
}

(3)设置任意属性

// 2. 设置任意属性:除name属性必须存在,其他属性可任意添加
let person2: {name: string, [propName: string]: any}
person2 = {
    name: 'Tom',
    age: 18,
    sex: 'male',
}

        一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集。

let person3: {
    name: string,
    age: number,
    // 以下语句报错:类型“number”的属性“age”不能赋给“string”索引类型“string”
    [propName: string]: string
}

// 以下定义正确:
let person3: {
    name: string,
    age: number,
    [propName: string]: number | string
}

2.3 函数 function

         在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression):

// 函数声明(Function Declaration)
function sum(x, y) {
    return x + y;
}

// 函数表达式(Function Expression)
let mySum = function (x, y) {
    return x + y;
};

// ES6 -> 箭头函数
let mySum2 = (x, y) => {
    return x + y
} 
let mySum3 = (x, y) => x + y 

        一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,如下:

// 函数声明(Function Declaration)
function sum(x: number, y: number): number {
    return x + y;
}

// 函数表达式(Function Expression)
// 以下类型定义是可以通过编译的
// 但代码实际上只对等号右侧的匿名函数进行了类型定义,而等号
/**
 *  以下类型定义是可以通过编译的,但代码实际上只对等号右侧的匿名函数进行了类型定义,
 *  而等号左边 mySum 的类型是类型推论而来,我们也可以手动添加类型,如 mySum4;
 *  以下的箭头函数同理;
 */
let mySum = function (x: number, y: number): number {
    return x + y;
};
let mySum4: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

// ES6 -> 箭头函数
let mySum2: (x: number, y: number) => number = (x: number, y: number): number => {
    return x + y
}

2.4 元组 tuple 

        固定长度的数组,可为每一个元素都指定类型。

let tom: [string, number] = ['Tom', 25];

2.5 枚举  enum

        枚举(Enum)类型用于取值被限定在一定范围内的场景。

        枚举使用 enum 关键字来定义,枚举成员会被赋值为从 0 开始递增的数字。当然也可以手动赋值,但是如果未手动赋值的枚举项与手动赋值的重复了,ts 并不会检查出来而导致出错,因此使用时要注意不要出现重复的情况。

        例如我们定义性别:female为0,male为1。存储数字比存储字母更合适,但是我们又想直观的看到我们取的选项是什么,新增的枚举类是一个不错的表示方式。(目前在我做的项目中,固定的枚举值一般通过定义对象的方式,而动态的枚举值通过后端接口返回的数据渲染,这个类型我还没用到过)。

// 简单的例子
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum Person {'Tom', 'Judy', 'Jay'}

const beToDuty: {day: Days, name: Person} = {
    day: Days.Mon, // 1
    name: Person.Tom // 0
}

// 给枚举项手动赋值,未手动赋值的枚举项会接着上一个枚举项递增
// Sun-7 Tue-2 Mon-1 Wed-2 Thu-3 Fri-4 Sat-5
enum Days {Sun = 7, Tue = 2, Mon = 1, Wed, Thu, Fri, Sat};

Tip1:any 和 unknown 类型的区别

(1)any 类型可以赋值给任意类型。

(2)unknown 类型的变量,不能直接赋值给其他变量。若要赋值,可使用“类型断言”。

let a: string;
let b: any;
let c: unknown;
a = 'test';
b = 1;
c = 1;

a = b; // any 类型可以赋值给任意类型而不进行检查,不安全
a = c; // 报错:不能将类型“unknown”分配给类型“string”

// 类型断言
a = <string>c 
a = c as string

Tip2:类型断言

        类型断言(Type Assertion)可以用来手动指定一个值的类型。

        类型断言只是为了“欺骗”编译器,使其在编译阶段不报错,它并没有对变量进行类型转换。如若使用不当,依旧可能在运行时报错。

        语法:(1)值 as 类型  (2)<类型>值。【在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用(1)。】

Tip3:void 与 never 的区别

(1)JavaScript 没有空值( void )的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数(或者返回 undefined 与 null,但这没什么意义),如下:

function fn1(): void {
    // return
    // return undefined
    // return null // vscode中会报错:不能将类型“null”分配给类型“void”
}

(2)never 表示永远不会返回结果。通常情况下,never 用于指示出现异常或无限循环的函数,或者表明函数总是会抛出异常或终止程序的运行。

// 抛出异常
function throwError(message: string): never {
  throw new Error(message);
}
// 无限循环
function infiniteLoop(): never {
  while (true) {
  }
}

3、类型推断

        如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。

        当变量的声明和赋值同时进行时,ts 编译器会自动判断变量的类型,此时可以省略掉类型声明。如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查。

// 报错
let myFavoriteNumber = 'seven'; // 推断成 string 类型
myFavoriteNumber = 7;

// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
let myFavoriteNumber; // 推断成 any 类型
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

4、联合类型

        联合类型(Union Types)表示取值可以为多种类型中的一种。

let myFavoriteNumber: string | number; // 可以为 string 或 number 类型
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
let sex: 'male' | 'female'; // 字面量类型,sex 只能取“male”和“female”
sex = 'male';
sex = 'female';
sex = 'other' // 报错:不能将类型“"other"”分配给类型“"male" | "female"”

三、面向对象+接口

        我目前项目的技术栈是 react+ts,都是用的函数式编程,比较少接触到类,主要是想学习一下接口。但确实是比较重要的概念还是需要学习一下。

1、面向对象

        面向对象是程序中一个非常重要的思想,简而言之就是程序之中所有的操作都需要通过对象来完成,在程序中一切皆是对象。例如:

  • 操作浏览器要使用 window 对象
  • 操作网页要使用 document 对象
  • 操作控制台要使用 console 对象

        一切操作都要通过对象,这就是所谓的面向对象。

        对象是什么?计算机程序的本质就是对现实事物的抽象,我们可以将具体的事物,比如人、汽车等等抽象为一个对象。程序也是对事物的抽象,一个事物到了程序中就变成一个对象。

        程序中所有的对象都被分成两个部分:数据和功能。例如人这个对象包含:[ 数据:姓名、年龄、身高等等 ]、[ 功能:说话、吃饭等等 ]。数据在对象中被称为属性,而功能被称为方法。

2、类

参考:https://ts.xcatliu.com/advanced/class.html

ES6中的类:ES6 入门教程 

2.1 类的概念

  • 类(Class):定义了一件事物的抽象特点,包含它的属性和方法;
  • 对象(Object):类的实例,通过 new 生成;
  • 面向对象(OOP)的三大特性:封装、继承、多态;
  • 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据;
  • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性;
  • 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat;
  • 存取器(getter & setter):用以改变属性的读取和赋值行为;
  • 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法;
  • 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现;
  • 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口;

2.2 类的定义

// 基本语法 —— 定义类
class 类名 {
    属性名: 类型;

    constructor(参数: 类型) {
        this.属性名 = 参数;
    }

    方法名() {
        ...
    }
}
// 一个简单的 Person 类示例
class PersonTS {
    // 定义属性类型
    name: string;
    age: number;
    static className: string = 'PersonTS' // 类属性

    // constructor -> 构造函数,在创建对象实例时调用
    constructor(name: string, age: number) {
        // 实例属性
        this.name = name;
        this.age = age;
    }

    // 实例方法
    printAge(){
        // 在方法中可以通过 this 来表示当前调用方法的对象
        console.log(`${this.name}今年${this.age}岁了!`);
    }

    // 类方法
    static sayHi(){
        console.log('hi.');
    }
}

const person1 = new PersonTS('Tom', 18);
const person2 = new PersonTS('John', 20);
console.log('person1: ', person1.name, person1.age); // person1: Tom 18
person1.printAge() // Tom今年18岁了!
console.log('person2: ', person2.name, person2.age); // person2: John 20
person2.printAge() // John今年20岁了!

console.log('PersonTS: ', PersonTS.className); // PersonTS: PersonTS
PersonTS.sayHi() // hi.

实例属性与方法:

        实例属性只能通过 constructor 构造函数中的 this.xxx 来定义,每次 new 一个对象时,都会调用类中的 constructor 构造函数,上述代码将 name 与 age 值传入以获得不同实例对象。实例的属性值需要在实例对象上取,例如 person1.name, person1.age。

        实例方法直接定义在类中,可以通过 this 使用当前实例对象的实例属性值。例如printAge。

静态属性与方法:

        使用 static 修饰符修饰的属性和方法称为静态属性(ES7)与静态方法,它们不需要实例化,而是直接通过类来调用。例如 PersonTS.className、PersonTS.sayHi()。

2.3 访问修饰符( pubilc | private | protected )

        TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected

  • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
  • private 修饰的属性或方法是私有的,不能在声明它的类的外部访问;【只能在类的内部访问】
  • protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的;【只能在类以及它的子类中被访问】
class Test {
    private privateArg: string;
    protected protectedArg: string;
    constructor(privateArg:string, protectedArg: string){
        this.privateArg = privateArg
        this.protectedArg = protectedArg
    }
    
    func(){
        console.log(this.privateArg);
        console.log(this.protectedArg);
    }
}

class SubTest extends Test {
    subFunc(){
        // 以下报错:属性“privateArg”为私有属性,只能在类“Test”中访问。
        console.log(this.privateArg);
        // 子类可访问 protected 定义的属性
        console.log(this.protectedArg);    
    }
}

const test = new Test('private', 'protected');
// 以下报错:属性“name”为私有属性,只能在类“Test”中访问
console.log(test.privateArg); 
// 以下报错:属性“protectedArg”受保护,只能在类“Test”及其子类中访问。
console.log(test.protectedArg);

2.4 存取器

        使用 getter 和 setter 可以改变属性的赋值和读取行为。在很多情况下,我们不希望属性是可以被任意修改的,例如 age 属性,我们不允许输入负值,需要对其做一些限制,此时我们就可以使用存取器来约束。

class Person {
    private _age: number;
    constructor(name: string, age: number) {
        this._age = age;
    }

    // TS 中设置 getter 方法的方式
    get age() {
        return this._age
    }

    // TS 中设置 setter 方法的方式
    set age(age: number) {
        // 对 age 属性进行限制
        if (age >= 0) {
            this._age = age
        }
    }
}

const person = new Person('Tom', 18)
person.age = 28;
console.log(person.age); // 28
person.age = -18;
console.log(person.age); // 28

2.5 类的继承

        假设我们创建了 Dog 类与 Cat 类,代码如下。我们发现两个类中存在共同的属性(name、age)与方法,此时我们考虑将相同的部分提取出来共用,这就可以用到“类的继承”。

// 分别实现 Dog 类与 Cat 类
class Dog {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHi() {
        console.log('汪汪汪!');
    }
}

class Cat {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHi() {
        console.log('喵喵喵~');
    }
}

const dog = new Dog('旺财', 3);
const cat = new Cat('咪咪', 2);

        我们使用 class Dog extends Animal 来实现继承。此时,Animal 被称为父类,Dog 被称为子类,子类将会拥有父类所有的方法和属性。

  • 如果希望在子类中添加一些父类没有的属性或方法,可直接在子类中添加。
  • super 关键字:使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法。如果在子类中使用构造函数,在子类构造函数中必须调用父类的构造函数。
  • 重写:在子类中添加和父类相同的方法,子类方法将会覆盖父类方法。
// Animal —— 父类
class Animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHi() {
        console.log('动物的叫声...');
    }
}

class Dog extends Animal {
    sex: string;
    constructor(name: string, age: number, sex: string) {
        // 继承父类的 name 与 age 属性
        super(name, age);
        // Dog 子类中新增的属性
        this.sex = sex;
    }

    // 重写父类方法
    sayHi() {
        console.log('汪汪汪!');
    }

    // 增加子类独有的方法
    run() {
        console.log('run...');
    }
}

class Cat extends Animal {
    sayHi() {
        console.log('喵喵喵~');
    }
}

const dog = new Dog('旺财', 3, 'male');
const cat = new Cat('咪咪', 2);

console.log('dog: ', dog.name, dog.sex); // dog: 旺财 male
dog.sayHi() // 汪汪汪!
dog.run() // run...
console.log('cat: ', cat.name, cat.age); // cat: 咪咪 2
cat.sayHi() // 喵喵喵~

2.6 抽象类

        abstract 用于定义抽象类和其中的抽象方法。

        (1)抽象类不允许被实例化。当我们希望某个类不能通过 new 创建实例,只用于继承时,可以使用抽象类。

abstract class Animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHi() {
        console.log('动物的叫声...');
    }
}

const dog = new Animal('旺财', 3) //报错:无法创建抽象类的实例。

        (2)抽象类中的抽象方法必须被子类实现。在上述代码中,我们能够发现 sayHi 这个方法并没有实际的作用,因为不同的动物会有不用的叫声,因此这类方法必须在子类中被重写,我们可以将其定义为抽象方法。

abstract class Animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    abstract sayHi(): void
}

3、接口

        在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。在程序设计里面,接口起到一种限制和规范的作用。基本语法如下:

interface Person {
    name: string;
    age?: number; // 可选属性:此属性可有可无
    readonly id: number; // 只读属性
    [propName: string]: any; // 任意属性
}

const person: Person = {
    name: 'Tom',
    sex: 'male',
    id: 5
}

3.1 类与接口

        实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。

        可以直接看这篇笔记,写了类实现接口、接口继承接口、接口继承类,可以直接参考:类与接口 · TypeScript 入门教程

3.2 函数类型接口

        函数本质上是一个特殊的对象,我们也可以用接口来定义函数的参数和返回值。

// 定义函数接口
interface func {
    (num: number, str: string): boolean
}

let func1: func = function (num: number, str: string) {
    return num === 1
}
let func2: func = (num: number, str: string) => num === 1 // 箭头函数

3.3 可索引接口

        可索引接口是一种描述数组和对象的接口,用来规范它们的索引类型和索引值类型等信息。

//对数组的约束
interface interArray {
    [index: number]: string
}
var arr: interArray = ['a', 'b']

3.4 react 组件 + 接口

        在使用 react 进行组件编写时,总会看到如下形式的传参,在不清楚具体参数的时候,一般会写 React.FC<any>,但是这样就没有意义了,使用接口可以在一定程度上对传参进行限制,防止一些不必要的错误,在调用组件时也可以给编写者提示需要传入什么参数。

interface Props {
    arg1: number
    arg2: string
    arg3?: boolean
    onFunc: (x: number, y: number) => void
    onFunc2: (values: string) => number
    [propName: string]: any
}

const TestComponents: React.FC<Props> = ({ arg1, arg2, arg3, onFunc, onFunc2 }: Props) => {

    return (
        <>
            测试组件
            属性有:{arg1}、{arg2}、{arg3}
            <button onClick={() => onFunc(1, 2)}>点击事件1</button>
            <button onClick={() => onFunc2('dd')}>点击事件2</button>
        </>
    )
}

export default TestComponents

3.5 tips1:接口与抽象类的区别

  • 接口使用 interface 关键字声明,抽象类使用 abstract 声明(类和成员);

  • 多继承:在接口中,一个类可以实现多个接口。这意味着一个类可以具备不同接口定义的属性和方法。而在抽象类中,一个类只能继承一个抽象类,由于JavaScript并不支持多继承,因此抽象类只能实现单一继承;

  • 默认实现:抽象类可以包含方法的实现细节,子类可以选择性地覆盖这些方法。接口不能包含实现细节,它只提供了属性和方法的定义,需要由实现接口的类来提供具体实现;

3.6  tips2:接口与类型别名的区别

        什么是类型别名?类型别名用来给一个类型起个新名字,使用 type 创建类型别名,类型别名不仅可以用来表示基本类型,还可以用来表示对象类型、联合类型、元组和交集。

type stringName = string; //基本类型
type combineName = string | number | boolean; // 联合类型
type Person = { // 对象类型
    name: string;
    age: number;
} 

区别:

  • 类型别名可以表示多种类型,interface 限于描述对象类型;

  • 类型别名不能重复声明,interface 可以重复声明,最终实现是所有同名的并集;

参考:typescript中接口(interface)和类型别名(type)的区别 - 掘金、详解TypeScript中type与interface的区别_javascript技巧_脚本之家

4、泛型

        参考:泛型 · TypeScript 入门教程

        泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

4.1 泛型的基本使用

        例如,我们想要定义一个函数,它的返回类型与输入的类型相同,但这个类型并不确定,我们可以这样做:

// 我们在函数名后添加了 <T>,其中 T 用来指代任意输入的类型
function generics<T>(arg: T): T{
    return arg
}

// 在调用时,可以指定具体的类型为 string
// 当然,也可以不手动指定,而让类型推断自动推算出来
const result1 = generics<string>('string')
const result2 = generics(2)

       定义泛型的时候,可以一次定义多个类型参数。

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]

4.2 泛型约束

        在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法。

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length);
    return arg;
}

// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.

        上例中,泛型 T 不一定包含属性 length,所以编译的时候报错了。这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束。

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

        上例中,我们使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状,也就是必须包含 length 属性,否则在编译时会报错。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙原生应用/元服务开发-长时任务

概述 功能介绍 应用退至后台后&#xff0c;对于在后台需要长时间运行用户可感知的任务&#xff0c;例如播放音乐、导航等。为防止应用进程被挂起&#xff0c;导致对应功能异常&#xff0c;可以申请长时任务&#xff0c;使应用在后台长时间运行。申请长时任务后&#xff0c;系统…

电脑弹窗“concrt140.dll文件找不到”,快速修复,亲测有效

很多小伙伴&#xff0c;在启动游戏或软件的时候&#xff0c;电脑会弹出错误提示框称““concrt140.dll文件找不到&#xff0c;程序无法运行”&#xff0c;不清楚是怎么回事&#xff0c;应该怎么办&#xff1f; 首先&#xff0c;我们先来了解““concrt140.dll文件找”是什么&a…

【AI视野·今日Robot 机器人论文速览 第七十四期】Wed, 10 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Wed, 10 Jan 2024 Totally 17 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Hold em and Fold em: Towards Human-scale, Feedback-Controlled Soft Origami Robots Authors Immanuel Ampomah Mensah, Je…

【前后端的那些事】前后端环境搭建+树形结构表格实现

文章目录 1. 前后端项目环境搭建2. table-tree2.1 后端准备2.2 前端准备 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&#xff0c;想写文章&#xff0c;录视频把这些内容记录下。但这些功能太零碎&#xff0c;如果为每个功能都单独搭建一个项目&#xff0…

【贪心】一手顺子

/** 贪心&#xff1a;将一个数当成一个组中最小的数&#xff0c;在根据该最小数找其它数。* 思路&#xff1a;将hand进行分组&#xff0c;假设hand长度为 n&#xff0c;必须n % groupSize 0才可以分组&#xff0c;否则返回false&#xff0c;* 使用哈希表记录每个数出现…

考研经验总结——目录

文章目录 一、写作顺序二、个人情况说明三、读评论四、一些小牢骚 一、写作顺序 我将准备从三个阶段开始介绍吧 考研前考研中考研后&#xff08;也就是现在我的这种情况&#xff09; 考研前我会分为&#xff1a;数学、专业课、政治、英语 四个部分来写 我应该会涉及&#xf…

AI赋能建筑设计 | VERYCLOUD睿鸿股份与亚马逊云科技协力为AIRI lab. 打造生成式AI应用案例

近年来&#xff0c;很多研究都致力于探索如何让建筑师借助人工智能的力量来促进并简化设计流程。生成式AI全球爆火以来&#xff0c;建筑设计领域也掀起了一场全新的思维变革。 AI为建筑设计带来更多可能 作为一家面向全球提供设计服务的企业&#xff0c;AIRI lab.计划推出一种…

Python教程41:使用turtle画蜡笔小新

---------------turtle源码集合--------------- Python教程39&#xff1a;使用turtle画美国队长盾牌 Python教程38&#xff1a;使用turtle画动态粒子爱心文字爱心 Python教程37&#xff1a;使用turtle画一个戴帽子的皮卡丘 Python教程36&#xff1a;海龟画图turtle写春联 …

【pytorch】使用pytorch构建线性回归模型-了解计算图和自动梯度

使用pytorch构建线性回归模型 线性方程的一般形式 衡量线性损失的一般形式-均方误差 pytorch中计算图的作用和优势 在 PyTorch 中&#xff0c;计算图&#xff08;Computational Graph&#xff09;是一种用于表示神经网络运算的数据结构。每个节点代表一个操作&#xff0c;例如…

【AWS】使用亚马逊云服务器创建EC2实例

目录 前言为什么选择 Amazon EC2 云服务器搭建 Amazon EC2 云服务器注册亚马逊账号登录控制台服务器配置免费套餐预览使用 Amazon EC2 云服务器打开服务器管理界面设置服务器区域填写实例名称选择服务器系统镜像选择实例类型创建密钥对网络设置配置存储启动实例查看实例 总结 前…

【天龙怀旧服】攻略day5

关键字&#xff1a; 天鉴扫荡、举贤、燕子水路 1】85天鉴任务可以扫荡 在流派选择npc那里&#xff0c;花费40交子即可扫荡100点&#xff0c;可以兑换10个灵武打造图&#xff1b; 此外打造图绑定不影响做出来的灵武绑定&#xff0c;只要对应的玉不绑灵武就不绑定 2】冠绝师门…

C#使用CryptoStream类加密和解密字符串

目录 一、CrytoStream的加密方法 二、CrytoStream的解密方法 三、实例 1.源码Form1.cs 2.类库Encrypt.cs 3.生成效果 在使用CryptoStream前要先引用命名空间using System.Security.Cryptography。 一、CrytoStream的加密方法 记住&#xff0c;不能再使用DESCryptoServi…

宏集案例丨宏集PC Runtime软件助推食品行业生产线数字化革新

来源&#xff1a;宏集科技 工业物联网 宏集案例丨宏集PC Runtime软件助推食品行业生产线数字化革新 原文链接&#xff1a;https://mp.weixin.qq.com/s/DwzVzifUiidNr-FT3Zfzpg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 01 前言 近年来&#xff0c;中国食品行业…

深入浅出Android dmabuf_dump工具

目录 dmabuf是什么&#xff1f; dmabuf_dump工具介绍(基于Android 14) Android.bp dmabuf_dump.cpp 整体架构结构如下 dmabuf_dump主要包含以下功能 前置背景知识 fdinfo 思考 bufinfo Dump整个手机系统的dmabuf Dump某个进程的dmabuf​​​​​​​ 以Table[buff…

Hive 的 安装与使用

目录 1 安装 MySql2 安装 Hive3 Hive 元数据配置到 MySql4 启动 Hive5 Hive 常用交互命令6 Hive 常见属性配置 Hive 官网 1 安装 MySql 为什么需要安装 MySql? 原因在于Hive 默认使用的元数据库为 derby&#xff0c;开启 Hive 之后就会占用元数据库&#xff0c;且不与其他客户…

Windows 远程控制之 PsExec

1、介绍&#xff1a; PsExec 是一种轻量级 telnet 替代品&#xff0c;可让你在其他系统上执行进程&#xff0c;并为控制台应用程序提供完整交互性&#xff0c;而无需手动安装客户端软件。 PsExec 最强大的用途包括在远程系统上启动交互式命令提示符&#xff0c;以及 IpConfig …

一篇文章彻底搞懂TiDB集群各种容量计算方式

背景 TiDB 集群的监控面板里面有两个非常重要、且非常常用的指标&#xff0c;相信用了 TiDB 的都见过&#xff1a; Storage capacity&#xff1a;集群的总容量 Current storage size&#xff1a;集群当前已经使用的空间大小 当你准备了一堆服务器&#xff0c;经过各种思考设计…

【JaveWeb教程】(21) MySQL数据库开发之多表设计:一对多、一对一、多对多的表关系 详细代码示例讲解

目录 2. 多表设计2.1 一对多2.1.1 表设计2.1.2 外键约束 2.2 一对一2.3 多对多2.4 案例 2. 多表设计 关于单表的操作(单表的设计、单表的增删改查)我们就已经学习完了。接下来我们就要来学习多表的操作&#xff0c;首先来学习多表的设计。 项目开发中&#xff0c;在进行数据库…

OCR字符识别:开始批量识别身份证信息

身份证信息批量识别OCR是一项解决方案&#xff0c;它能够将身份证照片打包成zip格式或通过URL地址进行提交&#xff0c;并能够识别照片中的文本信息。最终&#xff0c;用户可以将识别结果生成为excel文件进行下载。 API接口功能&#xff1a; 1. 批量识别&#xff1a;支持将多…

SPDK中常用的性能测试工具

本文主要介绍磁盘性能评估的方法&#xff0c;针对用户态驱动Kernel与SPDK中各种IO测试工具的使用方法做出总结。其中fio是一个常用的IO测试工具&#xff0c;可以运行在Linux、Windows等多种系统之上&#xff0c;可以用来测试本地磁盘、网络存储等的性能。为了和SPDK的fio工具相…