TypeScript 接口
TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。即如果一个东西走起来像鸭子、叫起来像鸭子,那它就是鸭子。
通过定义接口,为特定的结构赋予了一个明确的名称和规范。
在 TypeScript 中,接口(Interface)用于定义对象的形状,即对象应该具有哪些属性以及这些属性的类型。
使用 interface 关键字来定义接口
interface Person {name: string;age: number;
}
定义了一个名为 Person
的接口:
name
:必需的属性,且类型为字符串string
。age
: 必需的属性,类型为数字number
。
实现接口
一个对象或类可以明确声明它实现了某个接口,以满足接口定义的属性要求。
// person1 合法
let person1: Person = {name: "张三",age: 30
};// person2 不合法: 对象字面量只能指定已知属性,并且“likes”不在类型“Person”中。
let person2: Person = {name: "李四",age: 25,likes: "dog"
};
TypeScript 的类型系统非常严格,将一个对象指定为某个特定接口的类型时,它必须仅包含该接口中定义的属性,不能多也不能少。
所以,由于 likes
属性不在 Person
接口的定义中,TypeScript 会认为对象 person2
的结构不符合 Person
接口的要求,从而导致编译错误。
可选属性
在属性名后添加 ?
来标记属性为可选的。
interface Person {address?: string;
}
let person1: Person = {}; // 合法, 可以没有 address 属性
let person2: Person = {address: "xxx街道xxx小区"
};
定义了一个名为 Person
的接口:
address
:可选属性,其类型为字符串string
。创建符合Person
接口的对象时,address
属性可有可无。
只读属性
在属性名前用 readonly
来指定只读属性。
interface Person {readonly id: number;
}
// 类型 "{}" 中缺少属性 "id",但类型 "Person" 中需要该属性。
let person1: Person = {}; // Error: Property 'id' is missing in type '{}' but required in type 'Person'.// 赋值后,id 的值就不能再改变了。
let person2: Person = {id: 1,
};
person2.id = 2; // Error: 无法为“id”赋值,因为它是只读属性。
定义了一个名为 Person
的接口:
id
: 必需的属性,该属性只读。对象创建后,id
的值不能被重新赋值修改。
ReadonlyArray 类型用于表示一个只读的数组
创建 ReadonlyArray
后,就不能对其元素进行修改操作,例如添加、删除或修改元素的值:
let readonlyArr: ReadonlyArray<number> = [1, 2, 3];// 以下操作会报错,因为不能修改只读数组的元素
// 类型“readonly number[]”中的索引签名仅允许读取。
readonlyArr[0] = 4; // 类型“readonly number[]”上不存在属性“push”。
readonlyArr.push(4); // 类型“readonly number[]”上不存在属性“pop”。
readonlyArr.pop(); // 无法为“length”赋值,因为它是只读属性。
readonlyArr.length = 10;
ReadonlyArray<T>
与 Array<T>
的区别:
Array<T>
是普通的可修改数组类型,允许进行添加、删除、修改元素等操作。
普通数组可以使用push
、pop
、splice
等方法来修改数组的内容。ReadonlyArray<T>
去掉了这些可变的方法,以确保数组在被使用时不会被意外修改。
不能将只读数组直接赋值给普通数组,类型不兼容:
let arr: Array<number> = [1, 2, 3];
let readonlyArr: ReadonlyArray<number> = [1, 2, 3];// Error: The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
// 类型 "readonly number[]" 为 "readonly",不能分配给可变类型 "number[]"。
arr = readonlyArr
可以使用类型断言强制的类型转换:
arr = readonlyArr as number[];
ReadonlyArray
会把常用于需要确保数组不被意外修改的场景,以增强代码的安全性和可预测性。
readonly
vs const
readonly
(用于接口中的属性):- 应用于对象的属性,表示该属性在对象创建后不能被重新赋值。
interface Person {readonly name: string;
}let person: Person = { name: "张三" };
// 无法为“name ”重新赋值,因为它是只读属性。
person.name = "李四"; let mutablePerson = person;
// 无法为“name ”重新赋值,因为它是只读属性。
mutablePerson.name = "李四";
把 person
赋值给了 mutablePerson
,mutablePerson
实际上和 person
指向的是同一个对象。
由于 Person
接口中定义了 name
为只读属性,所以无论是通过 person
还是 mutablePerson
来尝试修改 name
的值,都是不被允许的,都会触发类型检查错误,提示不能对只读属性进行重新赋值。
这体现了 TypeScript 对接口中只读属性的严格类型检查,确保了在任何对该对象的操作中,都遵循了只读属性的约束。
const
- const声明一个只读的常量。一旦声明,常量的值就不能改变
- 对于基本数据类型(如数字、字符串、布尔值等),
const
声明的变量的值是不可变的。 - 对于引用数据类型(如对象、数组等),
const
只是保证变量的引用地址不能改变,但可以修改引用对象的内部属性。
const num = 5;
// 报错,不能重新给 const 基本类型变量赋值
num = 6; // Cannot assign to 'num' because it is a constant.const person = { name: "张三" };
person.name = "李四"; // 可以修改name 属性,因为person对象的引用地址没有改变person = { name: "李四" }; // 报错,不能重新给 const 引用类型变量 重新 赋值 引用地址
额外属性检查
定义了一个函数 printPersonInfo
,它接受一个参数 infoObj
,其类型为 Person
:
interface Person {name: string;age?: number;
}
function printPersonInfo(infoObj: Person) {console.log(infoObj);
}// Object literal may only specify known properties, and 'likes' does not exist in type 'Person'.
// 对象字面量只能指定已知属性,并且“likes”不在类型“Person”中。
printPersonInfo({ name: "李四", age: 25, likes: "dog" }); // 报错
调用printPersonInfo()
时,传入方法的参数 具有name
属性,满足 Person
接口的部分要求。age
是可选参数,可要可不要。有一个额外的likes
属性。
为什么会报错??
参数是以 对象字面量 的形式直接传递给printPersonInfo()
方法。
当把对象字面量赋值给变量或者作为参数传递的时候,对象字面量会被特殊对待而且会经过 额外属性检查。 如果一个对象字面量存在任何“目标类型”不包含的属性时,会编译错误。
如何绕开检查
- 使用类型断言绕开检查:
printPersonInfo({ name: "李四", age: 25, likes: "dog" } as Person);
- 添加索引签名
[propName: string]:any
:
interface Person {name: string;age?: number;[propName: string]:any;
}
[propName: string]: any
是一个索引签名。它表示可以有任意数量的额外属性,属性名是字符串类型,属性值可以是任何类型。
这样的接口定义提供了一定的灵活性。既规定了一些明确的必需和可选属性(name
和 age
),又允许对象具有其他任意的属性。
- 将这个对象赋值给一个另一个变量: 因为
myObj
不会经过额外属性检查,所以编译器不会报错。
let myObj = { name: "李四", age: 25, likes: "dog" }; // 参数合法
printPersonInfo(myObj);
对象 myObj
有额外的 likes
属性,为什么不报错?
因为对象 myObj
本身是一个普通对象, 它没有类型,不会经过额外属性检查。在作为参数传递时,myObj
具有 Person
接口要求的 name
、 age
属性,所以可以将 myObj
作为参数传递给 printPersonInfo
函数。
在 TypeScript 中,当将一个对象作为参数传递给一个函数,并且函数期望的参数类型是一个接口时,如果该对象包含了接口中定义的必要属性,即使它还具有额外的属性,也会被认为是合法的传递。
这体现了 TypeScript 基于结构的类型检查原则,只要对象满足接口定义的必要属性,就可以被视为该接口类型的对象。
函数类型
接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。
为了使用接口表示函数类型,我们需要给接口定义一个调用签名。 它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。
定义一个名为 MathOperation
的接口,它表示一个接受两个数字类型的参数 x
和 y
,并返回一个数字的函数类型:
interface MathOperation {(x: number, y: number): number;
}
我们可以像使用其它接口一样使用这个函数类型的接口。 下例展示了如何创建一个函数类型的变量,并将一个同类型的函数赋值给这个变量。
let sum: MathOperation;
sum = function(x: number, y: number): number{return x + y
}
// 简洁写法:let sum: MathOperation = (x, y) => x + y;
console.log( sum(10, 15) ); // 25
声明变量 sum
,其类型为 MathOperation
。
接下来,将一个匿名函数赋值给 sum
。这个匿名函数接受两个数字参数 x
和 y
,并返回它们的和,符合 MathOperation
接口定义的函数结构。
对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。
参数 x
和 y
可以用其他变量代替。
let sum: MathOperation;
sum = function(a: number, b: number): number{return a + b
}
函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的。 如果不想指定类型,TypeScript的类型系统会推断出参数类型,因为函数直接赋值给了 MathOperation
类型变量。 函数的返回值类型是通过其返回值推断出来的。
let sum: MathOperation;
sum = function(x, y){return x + y
}
可索引的类型
可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。
示例:
interface StringArray {[index: number]: string;
}let myArray: StringArray;
myArray = ["Bob", "Fred"];let myStr: string = myArray[0]; // Bob
定义StringArray
接口,它具有索引签名。 这个索引签名表示了当用 number
去索引StringArray
时会得到string
类型的返回值。
TypeScript支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用 number
来索引时,JavaScript会将它转换成 string
然后再去索引对象。 也就是说用 100
(一个number
)去索引等同于使用"100"
(一个string
)去索引,因此两者需要保持一致。
class Animal {name: string;
}
class Dog extends Animal {breed: string;
}// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
interface NotOkay {[x: number]: Animal;[x: string]: Dog;
}
在这段代码中,定义的 NotOkay
接口会导致错误。
因为在一个接口中同时定义了数字索引类型为 Animal
和字符串索引类型为 Dog
。
当使用索引来访问对象时:
- 使用数字索引,期望得到的是
Animal
类型; - 使用字符串索引,期望得到的是
Dog
类型。
但在实际情况中,这样的混合定义可能会导致混乱和不一致,因为无法明确在特定索引下应该返回哪种确切的类型。
这违反了 TypeScript 对于类型定义的一致性和明确性原则。
字符串索引签名能够很好的描述dictionary
模式,并且它们也会确保所有属性与其返回值类型相匹配。 因为字符串索引声明了 obj.property
和 obj["property"]
两种形式都可以。
示例中, name
的类型与字符串索引类型不匹配,所以类型检查器给出一个错误提示:
interface NumberDictionary {[index: string]: number;length: number; // 可以,length是number类型name: string // 错误,`name`的类型与索引类型返回值的类型不匹配
}
[index: string]: number;
这表示通过字符串索引访问这个对象时,返回的值应该是数字类型。
因为按照接口的定义,所有属性的值都应该是数字类型,但 name
的类型被定义为 string
,与索引返回值的类型不匹配。
将索引签名设置为只读,防止给索引赋值:
interface ReadonlyStringArray {readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // 类型“ReadonlyStringArray”中的索引签名仅允许读取。
类类型
在 TypeScript 中,“类类型”指的是使用 class
关键字定义的一种结构,用于描述具有特定属性、方法和行为的对象的模板。
类类型可以包含以下主要元素:
- 属性:描述对象的数据成员,具有特定的类型。
- 构造函数:用于初始化对象的属性,在创建对象实例时被调用。
- 方法:定义对象可以执行的操作。
implements
关键字
在 TypeScript 中,implements
关键字用于让一个类实现一个或多个接口。
当一个类使用 implements
关键字后跟一个接口名称时,它必须满足该接口所定义的所有属性和方法的要求。
这意味着:
- 类必须具有接口中定义的所有属性,并且属性的类型必须完全匹配。
- 类必须实现接口中定义的所有方法,方法的名称、参数列表和返回值类型都要与接口中的定义一致。
示例:
interface MyInterface {method1(): void;property1: string;
}class MyClass implements MyInterface {property1: string = "value";method1(): void {// 方法的实现}
}
在上述示例中,MyClass
类实现了 MyInterface
接口。它具有与接口中定义相同的属性 property1
和方法 method1
,并且属性的类型和方法的签名都符合接口的要求。
类静态部分与实例部分的区别
类是具有两个类型的:静态部分的类型和实例的类型。
定义一个名为 ClockConstructor
的接口:
interface ClockConstructor {new (hour: number, minute: number);
}
ClockConstructor
接口定义了一个构造函数的签名,要求实现这个接口的类必须具有一个接受两个参数(一个数字类型的 hour
和一个数字类型的 minute
)的构造函数。
然后定义了 Clock
类实现 ClockConstructor
接口:
class Clock implements ClockConstructor {constructor(h: number, m: number) { }
}
理论上:Clock
类的构造函数 constructor(h: number, m: number)
符合 ClockConstructor
接口中定义的构造函数要求,所以实现了该接口。
实际上:报错了!!
因为当一个类实现了一个接口时,只对其实例部分进行类型检查。 constructor
存在于类的静态部分,所以不在检查的范围内。
因此,需要直接操作类的静态部分。定义两个接口: ClockConstructor
为构造函数所用和ClockInterface为实例方法所用
interface ClockConstructor {new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {tick(): any;
}class Clock implements ClockInterface {constructor(h: number, m: number) { }tick() {console.log("beep beep");}
}
// 实例化
let myClock = new Clock(5, 30);
myClock.tick(); // beep beep
ClockConstructor
接口定义了一个构造函数的签名。ClockConstructor
接口规定了任何实现这个接口的构造函数,都必须接受两个数字类型的参数,并创建出符合ClockInterface
接口的对象。new
关键字表明这是在描述一个构造函数。(hour: number, minute: number)
是构造函数的参数列表。这表示该构造函数应接受两个number
类型的参数hour
和minute
。: ClockInterface
是构造函数的返回值类型。当使用这个构造函数创建对象时,所创建的对象应该符合ClockInterface
接口的定义。这就对通过这个构造函数创建的对象施加了一种约束,要求它们具有ClockInterface
中规定的属性和方法。- 这样定义的目的是为了统一规定创建时钟类的构造函数的参数和创建出的对象的类型。
ClockInterface
接口定义了一个方法tick()
,表示实现该接口的类需要具有这个方法。- 这意味着任何实现这个接口的类都需要有这个方法。
- 定义
Clock
类 实现ClockInterface
接口:Clock
类必须提供tick
方法。Clock
类的构造函数constructor(h: number, m: number)
符合ClockConstructor
接口中定义的构造函数要求。
注意:接口中定义的构造函数的返回值类型应该是一个具体的类型。
如果希望表示构造函数创建的对象不返回任何有意义的值,可以将返回值类型指定为 void
;如果希望指定创建的对象的类型,应该是一个具体的类或接口类型。
// 表示构造函数创建的对象不返回任何有意义的值,将返回值类型指定为 `void`
interface ClockConstructor {new (hour: number, minute: number): void;
}
// 返回值是一个具体的类型
interface ClockConstructor {new (hour: number, minute: number): ClockInterface; // 假设 ClockInterface 是已定义的接口
}
接口继承接口
一个接口可以继承自另一个接口,从而扩展其属性和方法;可以更灵活地将接口分割到可重用的模块里。
interface Person {name: string;age: number;
}interface Employee extends Person {salary: number;
}let Employee1: Employee = {name: "张三",age: 30,salary: 3000
};
一个接口可以继承多个接口,创建出多个接口的合成接口。
// Shape 接口定义了一个计算面积的方法 area
interface Shape {area(): number;
}
// Colorable 接口定义了一个表示颜色的属性 color
interface Colorable {color: string;
}// Square 接口继承了 Shape 和 Colorable 接口,并且添加了一个表示边长的属性 sideLength 。
interface Square extends Shape, Colorable {sideLength: number;
}
// MySquare 类 实现了 Square 接口
class MySquare implements Square {sideLength: number;color: string;constructor(sideLength: number, color: string) {this.sideLength = sideLength;this.color = color;}area(): number {return this.sideLength * this.sideLength;}
}let mySquare = new MySquare(5, "red");
console.log(mySquare.area()); // 25
console.log(mySquare.color); // red
Square
接口是包含了 Shape
和 Colorable
接口的特性的合成接口。
实现 Square
接口的类需要同时满足这三个接口的要求。
接口继承类
在 TypeScript 中,接口可以继承类。
当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private
和protected
成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。
示例:
class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}distanceFromOrigin(): number {return Math.sqrt(this.x * this.x + this.y * this.y);}
}interface Point3D extends Point {z: number;
}
class MyPoint3D implements Point3D {x: number;y: number;z: number;constructor(x: number, y: number, z: number) {this.x = x;this.y = y;this.z = z;}distanceFromOrigin(): number {// 重写父类的方法console.log(this.x, this.y, this.z);const distanceSquared = this.x * this.x + this.y * this.y + this.z * this.z;return Math.sqrt(distanceSquared);}
}let myP = new MyPoint3D(10, 20, 30);
console.log( myP.distanceFromOrigin() );
Point
类具有x
、y
属性和distanceFromOrigin
方法。Point3D
接口继承了Point
类。- 继承属性:接口
Point3D
继承了类Point
的属性x
和y
的声明。 - 不继承实现:接口
Point3D
继承了类Point
的属性和方法的声明,但它并没有继承类中方法的具体实现。比如,distanceFromOrigin
方法的实现不会被继承,实现Point3D
接口的类需要自己提供这个方法的实现(或者选择不实现,如果不是必须的)。 - 新增属性:在继承的基础上,接口
Point3D
增加了新的属性z
。
- 继承属性:接口
MyPoint3D
类实现了Point3D
接口。在MyPoint3D
类中:- 必须明确地实现接口中继承的属性
x
、y
以及新增的属性z
。 - 由于接口
Point3D
没有继承方法的实现,所以MyPoint3D
类需要提供distanceFromOrigin
方法的实现。
- 必须明确地实现接口中继承的属性
混合类型
在 TypeScript 中,混合类型(Hybrid Type)是指一个对象既具有属性又具有方法,同时还可能表现出一些函数的特征。
示例:
interface Counter {count: number;(): number;increment(): void;
}
// 声明变量counter,并指定它的类型是 Counter接口
let counter: Counter = {count: 0,increment() {this.count++;},// 作为函数被调用时返回当前计数() {return this.count;}
};counter.increment();
console.log(counter());
声明变量 counter
,并指定其类型为 Counter
接口类型。这意味着:
counter
变量必须具有符合 Counter
接口定义的结构和行为。它需要有一个数值类型的属性 count
,一个无返回值的方法 increment
,以及一个能返回数值的函数调用形式 ()
相关文章:
TypeScript 接口
TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。即如果一个东西走起来像鸭子、叫起来像鸭子,那它就是鸭子。 通过定义接口,为特定的结构赋予了一个明确的名称和规范。 在 TypeScript 中&a…...
基于JSP、java、Tomcat三者的项目实战--校园交易网(3)主页--添加商品功能
技术支持:JAVA、JSP 服务器:TOMCAT 7.0.86 编程软件:IntelliJ IDEA 2021.1.3 x64 前文三篇登录和注册功能的实现 基于JSP、java、Tomcat、mysql三层交互的项目实战--校园交易网(1)-项目搭建(前期准备工作…...
自定义SQL Server数据访问层:打造专属数据交互之门
自定义SQL Server数据访问层:打造专属数据交互之门 在软件开发中,数据访问层(Data Access Layer, DAL)扮演着至关重要的角色,它作为应用程序与数据库之间的桥梁,负责所有的数据存取操作。SQL Server作为一…...
【课程总结】Day15(中):图像分割之实例分割
前言 在上一章,我们通过学习了解了语义分割以及U-Net网络结构【课程总结】Day15(上):图像分割之语义分割。在本章,我们将学习了解图像分割中的实例分割以及相关的数据预处理注意事项。 图像分割 语义分割 语义分割…...
【Linux】常见指令
目录 一、指令的理解二、Linux的目录结构三、XShell 下的热键三、shell命令以及运行原理四、Linux常见的指令汇总1. ls 指令1.1 常见的一些有关 ls 的别名1.2 隐藏文件或目录1.3 * 的匹配 2. pwd 指令3. cd 指令3.1 cd . . 指令 4. touch指令5. mkdir指令6. rmdir指令 &&am…...
redis学习(一)
背景 redis是一个高性能的KV数据库,在工作中经常用到,可被用作缓存、分布式锁等,作为被高频使用的组件,了解其实现对工作有很大帮助(包括面试)。为此,在对redis有一定的使用、了解之后ÿ…...
LabVIEW在DCS中的优势
DCS(Distributed Control System,分布式控制系统)是一种用于工业过程控制的自动化系统。它将控制任务分散到多个控制单元中,通过网络连接和协调这些单元来实现对整个过程的监控和控制。DCS通常用于大型工业设施,如化工…...
JavaScript青少年简明教程:DOM和CSS简介
JavaScript青少年简明教程:DOM和CSS简介 DOM简介 DOM(Document Object Model)将文档表示为一个树形结构,其中每个节点都是一个对象,每个对象都有其自身的属性和方法。 通过对DOM的操作,开发者可以使用编…...
后端面试题日常练-day15 【Java基础】
题目 希望这些选择题能够帮助您进行后端面试的准备,答案在文末 Java中的自动装箱(Autoboxing)和拆箱(Unboxing)是指什么? a) 自动装箱是将基本数据类型转换为对应的包装类,拆箱是将包装类转换为…...
椭圆曲线加法运算
1. 定义 椭圆曲线 (Elliptic Curve) 不是函数,而是一条平面曲线,其方程是定义如下: y 2 x 3 a x b y^2x^3axb y2x3axb 其中,判别式 Δ − 16 ( 4 a 3 27 b 2 ) ≠ 0 \Delta -16(4a^327b^2)\neq 0 Δ−16(4a327b2)0。判别…...
采用计数排序的思想,解决只出现一次的数字
目录 问题 思路 代码 注意点: 问题 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常…...
网络云相册实现--nodejs后端+vue3前端
目录 主页面 功能简介 系统简介 api 数据库表结构 代码目录 运行命令 主要代码 server apis.js encry.js mysql.js upload.js client3 index.js 完整代码 主页面 功能简介 多用户系统,用户可以在系统中注册、登录及管理自己的账号、相册及照片。 每…...
程序设计基础(c语言)_补充_1
1、编程应用双层循环输出九九乘法表 #include <stdio.h> #include <stdlib.h> int main() {int i,j;for(i1;i<9;i){for(j1;j<i;j)if(ji)printf("%d*%d%d",j,i,j*i);elseprintf("%d*%d%-2d ",j,i,j*i);printf("\n");}return 0…...
【Unity】 HTFramework框架(五十四)【进阶篇】Deployment 轻量级资源部署管线
更新日期:2024年7月31日。 Github源码:[点我获取源码] 索引 Deployment 轻量级资源部署管线使用 Deployment一、创建部署配置二、编辑部署配置三、正式开始资源部署步骤一:资源打包步骤二:资源版本构建步骤三:资源版本…...
达梦数据库的系统视图v$cachesql
达梦数据库(DM Database)的系统视图V$CACHESQL用于显示有关数据库中缓存的SQL语句的信息。该视图提供了有关每个SQL语句的执行统计信息,帮助用户优化SQL性能和调试问题。 V$CACHESQL视图的主要字段 以下是V$CACHESQL视图中的一些关键字段&a…...
java基础 之 equals和==的区别
文章目录 浅谈“”特点比较基本类型比较引用类型 浅谈“equals”背景和使用重写equals自定义类为什么需要重写equals方法 总结附录代码及文章推荐 前言: 1、8大基本数据类型,它们的值直接代表了某种数据,不是对象的实例,不能使用n…...
学习STM32(1)--Keil软件安装与基本操作和Keil 软件高级应用
目录 1 引 言 2 实验目的 3 实验内容 3.1 认识单片机和STM32 3.2 安装、认识软件Keil和硬件STM32F103开发板 3.3 学习调试工程 3.4 Keil工程软件的配置 4 深入解析 思考一 1.以项目“12-GPIO输出—使用固件库点亮LED”为例子,认识本地工程文件夹…...
独立开发者系列(37)——理解async和await
1.理解同步与异步 同步就是执行某个任务A-B-C-D,就是严格按照顺序执行,可以理解为正常的代码逻辑,如果运行的代码都不是很消耗时间的情况系啊,同步可以减少编程的复杂度。但是对于请求远程服务结果的这种服务,如果同步…...
在C#中为图片添加数字水印的几种办法
最近在写个人项目时,有遇到需要将图片加上水印防止被盗取的需求。这里找了几种实现方式,可供有需要的朋友参考。 本身我不是搞算法这块的,所以这里只是找了一些实现,也没有继续深究下去。 以前在学校的时候从书上了解过可以将一…...
Vue的学习(二)
目录 一、class及style的绑定 1.v-bind:class绑定类名 绑定class为对象 编辑2. v-bind:class绑定类名 绑定class为对象 3.v-bind:class绑定类名 绑定class为数组 1) v-bind:class绑定类名 绑定class为数组 方法一: 2) v-bind:class绑定类名 绑定class为数组…...
PointNet和PointNet++论文解读
目录 一、导言 二、PointNet介绍 三、PointNet网络结构 1、损失函数 2、正则化 四、PointNet 1、分层次的点集抽象层 一、导言 PointNet来自CVPR2017,是最早直接处理点云数据用于计算机视觉的模型,并运用于分割、检测、场景理解任务,P…...
Pytest测试报告生成专题
在 pytest 中,你可以使用多个选项生成不同格式的测试报告。以下是几种常用的生成测试报告的方法: 1. 生成简单的测试结果文件 你可以使用 pytest 的 --junitxml 选项生成一个 XML 格式的测试报告,这个报告可以与 CI/CD 工具集成。 pytest --junitxml=report.xml这将在当前…...
【在Python中读取Excel文件内容】
在Python中读取Excel文件内容,常用的库有xlrd(主要用于读取.xls文件,但不支持.xlsx的较新版本),以及openpyxl(专门用于读取和写入.xlsx文件)和pandas(提供了一个更高级别的接口来处理…...
尚品汇-首页三级分类实现-nginx静态代理生成的静态页面(二十六)
目录: (1)问题详解 (2)首页商品分类实现 (3)修改web-all模块 (4)页面渲染 (1)问题详解 (2)首页商品分类实现 前面做了…...
HTML 段落
HTML 段落 概述 HTML(超文本标记语言)是构建网页的标准语言,而段落是构成网页内容的基本单元。在HTML中,段落是通过<p>标签来定义的。本文将详细介绍HTML段落的相关知识,包括段落的基本结构、样式设置、以及在…...
Http自定义Header导致的跨域问题
最近写一个小项目,前后端分离,在调试过程中访问远程接口,出现了CORS问题,接口使用的laravel框架,于是添加了解决跨域的中间件,但是前端显示仍存在跨域问题,以为自己写的有问题,检查了…...
20240805 每日AI必读资讯
世界首例!AI机器人做牙科手术,8倍速诊疗比人类医生更精准 - Perceptive:让人工智能控制的自主机器人,首次对人类患者进行了全过程的牙科手术,速度大约是人类牙医的8倍。 - 两项新技术 1、OCT 3D成像系统:…...
COMSOL金属氢化物-放氢过程
在此记录下放氢过程的软件设置思路 1、采用的是"达西定律""层流" 物理场,其中"层流"物理场选择了”弱可压缩流动“,这里主要是选择”可压缩流动“的话,算出来的瞬时流量值跟实测差距太大了。 2、设置"达西…...
Unity2D在处理精灵表过程中出现不清晰的解决方法
问题阐述 在我们拿到一张精灵表的时候,我们通常要进行切割。但这样往往导致切割的效果不是很好,这里举一个简单的例子。 这是举例子用到的精灵表 我们先对他进行切割处理。 将single改为Multiope 进入精灵编辑器后,我们选择切割方式 此时我…...
C语言第13篇
1.下面程序是计算n个数的平均值,请填空.______ #include<stdio.h> void main( ) { int i,n; float x,avg0.0; scanf("%d",&n); for(i0;i<n;i) { scanf("%f",&x); avgavg______; } avg________; printf("avg%f\n",avg); } A) …...
Meta Reality Labs:巨额亏损背后的挑战与展望
一、财务概况 自2020年以来,Meta的Reality Labs部门累计亏损已超过450亿美元,其中2023年的亏损达到160亿美元,2024年第一季度亏损38亿美元,分析师预计第二季度亏损可能接近50亿美元。尽管投入巨大,Reality Labs的收入却呈现下降趋势,与不断增加的支出形成鲜明对比。 二…...
linux安装docker(实操教程)
一、安装前准备工作 1.查看服务器操作系统版本 2.查看服务器的操作系统内核版本 3.安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2如果不是root用户登陆的系统,需要手动输入sudo -i切换到root帐户 4.设置阿里云docker-ce镜像源 yum-c…...
隐写工具steghide linux编译安装
1、git clone https://github.com/StefanoDeVuono/steghide.git 2、autoreconf -i 3、./configure 4、make 编译完成后再src目录下又steghide执行下程序 报错:configure: error: cannot find required auxiliary files: compile时需要执行autoreconf 如果往j…...
山寨手机 老手机 山寨平板 提高速度 cpu超频的方法360超级root和setup
第一,挂机 ,按音量键 ,看机器的配置,注意,山寨机器的 安卓版本不可信啊,安卓4.4.2会标注安卓10 第二 ,下载360超级root, http://2012rs.mysxl.cn/ https://xdaforums.com/t/setcpu-for-root-us…...
【两整数之和】python刷题记录
R3-位运算专题。 仲夏之约,留尺一寸,小记一事,算是了结。 无进位和 与 异或运算 规律相同,进位 和 与运算 规律相同(并需左移一位) 牛啊牛啊 class Solution:def getSum(self, a: int, b: int) -> int…...
常见cms漏洞之dedecms
DedeCMS是织梦团队开发PHP 网站管理系统,它以简单、易用、高效为特色,组建出各种各样各具特色的网站,如地方门户、行业门户、政府及企事业站点等。 下载地址请网上自行寻找 搭建方式选择php study 首先搭建环境 #前台http://localhost/dedecm…...
基于微信小程序的微课堂笔记的设计与实现(源码+论文+部署讲解等)
博主介绍:✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍:我是程序员阿龙ÿ…...
如何构建AI产品:OpenAI与前Shopify产品负责人Miqdad Jaffer的经验分享
一、引言 构建AI产品是一项复杂且充满挑战的任务,尤其是当涉及到面向消费者的解决方案时。在最近的一期播客节目中,OpenAI 和前Shopify产品负责人 Miqdad Jaffer 分享了他在构建AI产品的经验和策略。下面我们将探讨构建AI产品的最佳实践,以及…...
C++的结构体、联合体、枚举类型(一)
1.C++的结构体 2.C++的联合体 3.C++的枚举类型 1.C++的结构体 (1)C++中定义结构体变量,可以省略struct关键字 struct XX{…}; XX x;//定义结构体变量直接省略struct(2)C++结构体中可以直接定义函数,谓之成员函数(又叫方法)(3)在成员函数中可以直接访问该结构体的成员变…...
白骑士的PyCharm教学高级篇 3.5 团队协作与集成开发
系列目录 上一篇:白骑士的PyCharm教学高级篇 3.4 服务器部署与配置 在现代软件开发中,团队协作和集成开发环境(IDE)的使用至关重要。PyCharm不仅提供了强大的个人开发支持,还为团队协作和集成开发提供了丰富的功能和工…...
c++ 21 指针
*像一把钥匙 通过钥匙去找内存空间 间接修改内存空间的值 不停的给指针赋值 等于不停的更改指针的指向 指针也是一种数据类型 指针做函数参数怎么看都不可以 指针也是一个数据类型 是指它指向空间的数据类习惯 作业 野指针 向null空间地址copy数据 不断改变指针指向 …...
书籍将整数字符串转成整数值(5)0804
题目 给定一个字符串str,如果str符合日常书写的整数形式,并且属于32位整数的范围,返回str所代表的整数值,否则返回0。 举例 str“123” 返回 123 str“023” 因为023 不符合日常的书写习惯,所以返回0 str“A13” …...
计网:从输入URL到网页显示期间发生了什么
1、URL包含的信息 我们输入的url中包含着一些信息: http:表示的此次我们使用的什么协议/www.baidu.com:表示的是我们想要访问的服务器名称,也就是域名dir3/home.html:表示我们所要访问的资源 2、通过DNS解析URL获得I…...
pg数据库存储过程
一、存储过程 CREATE OR REPLACE PROCEDURE public.p_dm_stock_fx_hangye_d(IN dt_date character varying) LANGUAGE plpgsql AS $procedure$ begin delete from dm_stock_fx_hangye_d where stock_date dt_date; commit; insert into dm_stock_fx_hangye_d select t…...
Arduino PID库 (2) –微分导致的过冲
Arduino PID库 (2) – Derivative Kick 参考:手把手教你看懂并理解Arduino PID控制库——微分冲击 pid内容索引-CSDN博客 Arduino PID库 (1)– 简介 问题 此修改将稍微调整derivative term。目标是消除一种称为“…...
基于Tensorflow.js的花卉识别编程实践
使用TensorFlow.js进行编程有许多优点,特别适合开发机器学习和深度学习的应用。TensorFlow.js可以直接在浏览器中运行,无需服务器或特殊环境配置。这使得开发者可以轻松地创建和部署基于Web的机器学习应用。TensorFlow.js提供了许多预训练模型࿰…...
繁简之争:为什么手机芯片都是 ARM
RISC 和 CISC 指令集 之前的文章《揭秘 CPU 是如何执行计算机指令的》中说到,如果从软件的角度来讲,CPU 就是一个执行各种计算机指令(Instruction Code)的逻辑机器。 计算机指令集是计算机指令的集合,包括各种类型的…...
《机器人SLAM导航核心技术与实战》第1季:第8章_激光SLAM系统
视频讲解 【第1季】8.第8章_激光SLAM系统-视频讲解【第1季】8.1.第8章_激光SLAM系统_Gmapping算法-视频讲解【第1季】8.2.第8章_激光SLAM系统_Cartographer算法-视频讲解【第1季】8.3.第8章_激光SLAM系统_LOAM算法-视频讲解 第1季:第8章_激光SLAM系统 先 导 课第…...
Qt之Gui
组件依赖关系 应用 #mermaid-svg-GADicZtZJRVVUeiF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GADicZtZJRVVUeiF .error-icon{fill:#552222;}#mermaid-svg-GADicZtZJRVVUeiF .error-text{fill:#552222;stroke:#…...
Redis的回收策略(淘汰策略)
volatile-lru :从已设置过期时间的数据集( server.db[i].expires )中挑选最近最少使用的数据淘汰 volatile-ttl : 从已设置过期时间的数据集( server.db[i].expires ) 中挑选将要过期的数据淘汰 volatile…...