TypeScript:模块

一、前言

关于术语的一点说明: 请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。

二、简介

从ECMAScript 2015开始,JavaScript引入了模块的概念。TypeScript也沿用这个概念。

模块在其自身的作用域里执行,而不是在全局作用域里;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用 import形式之一。

模块是自声明的;两个模块之间的关系是通过在文件级别上使用imports和exports建立的。

模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于Node.js的 CommonJS和服务于Web应用的Require.js。

TypeScript与ECMAScript 2015一样,任何包含顶级import或者export的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的(因此对模块也是可见的)。

三、导出

3.1 导出声明

任何声明(比如变量,函数,类,类型别名或接口)都能够通过添加export关键字来导出。

export interface StringValidator {isAcceptable(s: string): boolean;
}export const numberRegexp = /^[0-9]+$/;export class ZipCodeValidator implements StringValidator {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);}
}let zipCodeValidator = new ZipCodeValidator()
let result = zipCodeValidator.isAcceptable("12345")
console.log(`result = ${result}`)

运行结果
在这里插入图片描述

3.2 导出语句

导出语句很便利,因为我们可能需要对导出的部分重命名,所以上面的例子可以这样改写:

class ZipCodeValidator2 implements StringValidator {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);}
}
export { ZipCodeValidator2 };
export { ZipCodeValidator2 as mainValidator };
3.3 重新导出

我们经常会去扩展其它模块,并且只导出那个模块的部分内容。 重新导出功能并不会在当前模块导入那个模块或定义一个新的局部变量。
ParseIntBasedZipCodeValidator.ts

export class ParseIntBasedZipCodeValidator {isAcceptable(s: string) {return s.length === 5 && parseInt(s).toString() === s;}
}// 导出原先的验证器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";

或者一个模块可以包裹多个模块,并把他们导出的内容联合在一起通过语法:export * from “module”。

AllValidators.ts

export * from "./Validation"; // exports interface StringValidator
export * from "./ParseIntBasedZipCodeValidator"; // exports class ParseIntBasedZipCodeValidator
export * from "./ZipCodeValidator";  // exports class ZipCodeValidator

四、导入

模块的导入操作与导出一样简单。 可以使用以下 import形式之一来导入其它模块中的导出内容。

导入一个模块中的某个导出内容

import { ZipCodeValidator } from "./ZipCodeValidator";let myValidator1 = new ZipCodeValidator();

可以对导入内容重命名

import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator2 = new ZCV();

将整个模块导入到一个变量,并通过它来访问模块的导出部分

import * as validator from "./ZipCodeValidator";
let myValidator3 = new validator.ZipCodeValidator();
4.1 具有副作用的导入模块

尽管不推荐这么做,一些模块会设置一些全局状态供其它模块使用。 这些模块可能没有任何的导出或用户根本就不关注它的导出。 使用下面的方法来导入这类模块:

import "./my-module.js";

五、默认导出

每个模块都可以有一个default导出。 默认导出使用 default关键字标记;并且一个模块只能够有一个default导出。 需要使用一种特殊的导入形式来导入 default导出。

default导出十分便利。 比如,像JQuery这样的类库可能有一个默认导出 jQuery或$,并且我们基本上也会使用同样的名字jQuery或$导出JQuery。

Query.d.ts

declare let $: JQuery;
export default $;

App.ts

import $ from "JQuery";$("button.continue").html( "Next Step..." );

类和函数声明可以直接被标记为默认导出。 标记为默认导出的类和函数的名字是可以省略的。

ZipCodeValidator.ts

export default class ZipCodeValidator2 {static numberRegexp = /^[0-9]+$/;isAcceptable(s: string) {return s.length === 5 && ZipCodeValidator2.numberRegexp.test(s);}
}
import validator from "./ZipCodeValidator";let myValidator = new validator();

或者

StaticZipCodeValidator.ts

const numberRegexp = /^[0-9]+$/;export default function (s: string) {return s.length === 5 && numberRegexp.test(s);
}
import validate1 from "./StaticZipCodeValidator";let strings = ["Hello", "98052", "101"];// Use function validate
strings.forEach(s => {console.log(`"${s}" ${validate1(s) ? " matches" : " does not match"}`);
});

default导出也可以是一个值

OneTwoThree.ts

export default "123";
import num from "./OneTwoThree";
console.log(num); // "123"

export = 和 import = require()
CommonJS和AMD的环境里都有一个exports变量,这个变量包含了一个模块的所有导出内容。

CommonJS和AMD的exports都可以被赋值为一个对象, 这种情况下其作用就类似于 es6 语法里的默认导出,即 export default语法了。虽然作用相似,但是 export default 语法并不能兼容CommonJS和AMD的exports。

为了支持CommonJS和AMD的exports, TypeScript提供了export =语法。

export =语法定义一个模块的导出对象。 这里的对象一词指的是类,接口,命名空间,函数或枚举。

若使用export =导出一个模块,则必须使用TypeScript的特定语法import module = require(“module”)来导入此模块。

ZipCodeValidator2.ts

let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);}
}
// An export assignment cannot be used in a module with other exported elements.t
// 所以创建 ZipCodeValidator2.ts文件
export = ZipCodeValidator;
import zip2 = require("./ZipCodeValidator2");// Some samples to try
let strings2 = ["Hello", "98052", "101"];// Validators to use
let validator5 = new zip2();// Show whether each string passed each validator
strings2.forEach(s => {console.log(`"${ s }" - ${ validator5.isAcceptable(s) ? "matches" : "does not match" }`);
});

六、生成模块代码

根据编译时指定的模块目标参数,编译器会生成相应的供Node.js (CommonJS),Require.js (AMD),UMD,SystemJS或ECMAScript 2015 native modules (ES6)模块加载系统使用的代码。 想要了解生成代码中 define,require 和 register的意义,请参考相应模块加载器的文档。

下面的例子说明了导入导出语句里使用的名字是怎么转换为相应的模块加载器代码的。

SimpleModule.ts

import m = require("./ZipCodeValidator2");
let validator6 = new m();
export let t = validator6.add(2) + 1;

AMD / RequireJS SimpleModule.js

define(["require", "exports", "./ZipCodeValidator2"], function (require, exports, mod_1) {exports.t = mod_1.add(1) + 1;
});

CommonJS / Node SimpleModule.js

let mod_1 = require("./mod");
exports.t = mod_1.add(2) + 1;

UMD SimpleModule.js

(function (factory) {if (typeof module === "object" && typeof module.exports === "object") {let v = factory(require, exports); if (v !== undefined) module.exports = v;}else if (typeof define === "function" && define.amd) {define(["require", "exports", "./ZipCodeValidator2"], factory);}
})(function (require, exports) {let mod_1 = require("./ZipCodeValidator2");exports.t = mod_1.add(3) + 1;
});

System SimpleModule.js

System.register(["./ZipCodeValidator2"], function(exports_1) {let mod_1;let t;return {setters:[function (mod_1_1) {mod_1 = mod_1_1;}],execute: function() {exports_1("t", t = mod_1.add(4) + 1);}}
});

Native ECMAScript 2015 modules SimpleModule.js

import { something } from "./ZipCodeValidator2";
export let t = something + 1;

七、简单示例

下面我们来整理一下前面的验证器实现,每个模块只有一个命名的导出。

为了编译,我们必需要在命令行上指定一个模块目标。对于Node.js来说,使用–module commonjs; 对于Require.js来说,使用–module amd。比如:

tsc --module commonjs Test.ts

编译完成后,每个模块会生成一个单独的.js文件。 好比使用了reference标签,编译器会根据 import语句编译相应的文件。
Validation.ts

export interface StringValidator {isAcceptable(s: string): boolean;
}

LettersOnlyValidator.ts

import { StringValidator } from "./Validation";const lettersRegexp = /^[A-Za-z]+$/;export class LettersOnlyValidator implements StringValidator {isAcceptable(s: string) {return lettersRegexp.test(s);}
}

ZipCodeValidator2.ts

import { StringValidator } from "./Validation";const numberRegexp = /^[0-9]+$/;export class ZipCodeValidator implements StringValidator {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);}
}

Test.ts

import { StringValidator } from "./Validation";
import { ZipCodeValidator } from "./ZipCodeValidator";
import { LettersOnlyValidator } from "./LettersOnlyValidator";// Some samples to try
let strings = ["Hello", "98052", "101"];// Validators to use
let validators: { [s: string]: StringValidator; } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();// Show whether each string passed each validator
strings.forEach(s => {for (let name in validators) {console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);}
});

八、可选的模块加载和其它高级加载场景

有时候,你只想在某种条件下才加载某个模块。 在TypeScript里,使用下面的方式来实现它和其它的高级加载场景,我们可以直接调用模块加载器并且可以保证类型完全。

编译器会检测是否每个模块都会在生成的JavaScript中用到。 如果一个模块标识符只在类型注解部分使用,并且完全没有在表达式中使用时,就不会生成 require这个模块的代码。 省略掉没有用到的引用对性能提升是很有益的,并同时提供了选择性加载模块的能力。

这种模式的核心是import id = require(“…”)语句可以让我们访问模块导出的类型。 模块加载器会被动态调用(通过 require),就像下面if代码块里那样。 它利用了省略引用的优化,所以模块只在被需要时加载。 为了让这个模块工作,一定要注意 import定义的标识符只能在表示类型处使用(不能在会转换成JavaScript的地方)。

为了确保类型安全性,我们可以使用typeof关键字。 typeof关键字,当在表示类型的地方使用时,会得出一个类型值,这里就表示模块的类型。

示例:Node.js里的动态模块加载

declare function require(moduleName: string): any;import { ZipCodeValidator as Zip } from "./ZipCodeValidator";if (needZipValidation) {let ZipCodeValidator: typeof Zip = require("./ZipCodeValidator");let validator = new ZipCodeValidator();if (validator.isAcceptable("...")) { /* ... */ }
}

示例:require.js里的动态模块加载

declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void;import * as Zip from "./ZipCodeValidator";if (needZipValidation) {require(["./ZipCodeValidator"], (ZipCodeValidator: typeof Zip) => {let validator = new ZipCodeValidator.ZipCodeValidator();if (validator.isAcceptable("...")) { /* ... */ }});
}

示例:System.js里的动态模块加载

declare const System: any;import { ZipCodeValidator as Zip } from "./ZipCodeValidator";if (needZipValidation) {System.import("./ZipCodeValidator").then((ZipCodeValidator: typeof Zip) => {var x = new ZipCodeValidator();if (x.isAcceptable("...")) { /* ... */ }});
}

九、 使用其它的JavaScript库

要想描述非TypeScript编写的类库的类型,我们需要声明类库所暴露出的API。

我们叫它声明因为它不是“外部程序”的具体实现。 它们通常是在 .d.ts文件里定义的。 如果你熟悉C/C++,你可以把它们当做 .h文件。 让我们看一些例子。

9.1 外部模块

在Node.js里大部分工作是通过加载一个或多个模块实现的。 我们可以使用顶级的 export声明来为每个模块都定义一个.d.ts文件,但最好还是写在一个大的.d.ts文件里。 我们使用与构造一个外部命名空间相似的方法,但是这里使用 module关键字并且把名字用引号括起来,方便之后import。 例如:

node.d.ts (simplified excerpt)

declare module "url" {export interface Url {protocol?: string;hostname?: string;pathname?: string;}export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;
}declare module "path" {export function normalize(p: string): string;export function join(...paths: any[]): string;export let sep: string;
}

现在我们可以/// node.d.ts并且使用import url = require(“url”);或import * as URL from "url"加载模块。

/// <reference path="node.d.ts"/>
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");
9.2 外部模块简写

假如你不想在使用一个新模块之前花时间去编写声明,你可以采用声明的简写形式以便能够快速使用它。

declarations.d.ts

declare module "hot-new-module";

简写模块里所有导出的类型将是any。

import x, {y} from "hot-new-module";
x(y);
9.3 模块声明通配符

某些模块加载器如SystemJS 和 AMD支持导入非JavaScript内容。 它们通常会使用一个前缀或后缀来表示特殊的加载语法。 模块声明通配符可以用来表示这些情况。

declare module "*!text" {const content: string;export default content;
}
// Some do it the other way around.
declare module "json!*" {const value: any;export default value;
}
9.4 UMD模块

有些模块被设计成兼容多个模块加载器,或者不使用模块加载器(全局变量)。 它们以 UMD模块为代表。 这些库可以通过导入的形式或全局变量的形式访问。 例如:

math-lib.d.ts

export function isPrime(x: number): boolean;
export as namespace mathLib;

之后,这个库可以在某个模块里通过导入来使用:

import { isPrime } from "math-lib";
isPrime(2);
mathLib.isPrime(2); // 错误: 不能在模块内使用全局定义。

它同样可以通过全局变量的形式使用,但只能在某个脚本(指不带有模块导入或导出的脚本文件)里。

mathLib.isPrime(2);

十、创建模块结构指导

10.1 尽可能地在顶层导出

用户应该更容易地使用你模块导出的内容。 嵌套层次过多会变得难以处理,因此仔细考虑一下如何组织你的代码。

从你的模块中导出一个命名空间就是一个增加嵌套的例子。 虽然命名空间有时候有它们的用处,在使用模块的时候它们额外地增加了一层。 这对用户来说是很不便的并且通常是多余的。

导出类的静态方法也有同样的问题 - 这个类本身就增加了一层嵌套。 除非它能方便表述或便于清晰使用,否则请考虑直接导出一个辅助方法。

如果仅导出单个 class 或 function,使用 export default

就像“在顶层上导出”帮助减少用户使用的难度,一个默认的导出也能起到这个效果。 如果一个模块就是为了导出特定的内容,那么你应该考虑使用一个默认导出。 这会令模块的导入和使用变得些许简单。 比如:

MyClass.ts

export default class SomeType {constructor() { ... }
}

MyFunc.ts

export default function getThing() { return 'thing'; }

Consumer.ts

import t from "./MyClass";
import f from "./MyFunc";
let x = new t();
console.log(f());

运行结果
在这里插入图片描述
对用户来说这是最理想的。他们可以随意命名导入模块的类型(本例为t)并且不需要多余的(.)来找到相关对象。

如果要导出多个对象,把它们放在顶层里导出
MyThings.ts

export class SomeType { /* ... */ }
export function someFunc() { /* ... */ }

相反地,当导入的时候:

明确地列出导入的名字
Consumer.ts

import { SomeType, someFunc } from "./MyThings";
let x = new SomeType();
let y = someFunc();

使用命名空间导入模式当你要导出大量内容的时候
MyLargeModule.ts

export class Dog {  }
export class Cat {  }
export class Tree {  }
export class Flower {  }

Consumer.ts

import * as myLargeModule from "./MyLargeModule";
let x3 = new myLargeModule.Dog();
10.2 使用重新导出进行扩展

你可能经常需要去扩展一个模块的功能。 JS里常用的一个模式是JQuery那样去扩展原对象。 如我们之前提到的,模块不会像全局命名空间对象那样去 合并。 推荐的方案是 不要去改变原来的对象,而是导出一个新的实体来提供新的功能。

假设Calculator.ts模块里定义了一个简单的计算器实现。 这个模块同样提供了一个辅助函数来测试计算器的功能,通过传入一系列输入的字符串并在最后给出结果。

Calculator.ts

export class Calculator {private current = 0;private memory = 0;private operator: string = "";protected processDigit(digit: string, currentValue: number) {if (digit >= "0" && digit <= "9") {return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0));}}protected processOperator(operator: string) {if (["+", "-", "*", "/"].indexOf(operator) >= 0) {return operator;}}protected evaluateOperator(operator: string, left: number, right: number): number {switch (this.operator) {case "+": return left + right;case "-": return left - right;case "*": return left * right;case "/": return left / right;}}private evaluate() {if (this.operator) {this.memory = this.evaluateOperator(this.operator, this.memory, this.current);}else {this.memory = this.current;}this.current = 0;}public handleChar(char: string) {if (char === "=") {this.evaluate();return;}else {let value = this.processDigit(char, this.current);if (value !== undefined) {this.current = value;return;}else {let value = this.processOperator(char);if (value !== undefined) {this.evaluate();this.operator = value;return;}}}throw new Error(`Unsupported input: '${char}'`);}public getResult() {return this.memory;}
}export function test(c: Calculator, input: string) {for (let i = 0; i < input.length; i++) {c.handleChar(input[i]);}console.log(`result of '${input}' is '${c.getResult()}'`);
}

下面使用导出的test函数来测试计算器。

TestCalculator.ts

import { Calculator, test } from "./Calculator";let c = new Calculator();
test(c, "1+2*33/11="); // prints 9

现在扩展它,添加支持输入其它进制(十进制以外),让我们来创建ProgrammerCalculator.ts。

ProgrammerCalculator.ts。

import { Calculator } from "./Calculator";class ProgrammerCalculator extends Calculator {static digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];constructor(public base: number) {super();const maxBase = ProgrammerCalculator.digits.length;if (base <= 0 || base > maxBase) {throw new Error(`base has to be within 0 to ${maxBase} inclusive.`);}}protected processDigit(digit: string, currentValue: number) {if (ProgrammerCalculator.digits.indexOf(digit) >= 0) {return currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit);}}
}// Export the new extended calculator as Calculator
export { ProgrammerCalculator as Calculator };// Also, export the helper function
export { test } from "./Calculator";

新的ProgrammerCalculator模块导出的API与原先的Calculator模块很相似,但却没有改变原模块里的对象。 下面是测试ProgrammerCalculator类的代码:

TestProgrammerCalculator.ts

import { Calculator, test } from "./ProgrammerCalculator";let c = new Calculator(2);
test(c, "001+010="); // prints 3
10.3 模块里不要使用命名空间

当初次进入基于模块的开发模式时,可能总会控制不住要将导出包裹在一个命名空间里。 模块具有其自己的作用域,并且只有导出的声明才会在模块外部可见。 记住这点,命名空间在使用模块时几乎没什么价值。

在组织方面,命名空间对于在全局作用域内对逻辑上相关的对象和类型进行分组是很便利的。 例如,在C#里,你会从 System.Collections里找到所有集合的类型。 通过将类型有层次地组织在命名空间里,可以方便用户找到与使用那些类型。 然而,模块本身已经存在于文件系统之中,这是必须的。 我们必须通过路径和文件名找到它们,这已经提供了一种逻辑上的组织形式。 我们可以创建 /collections/generic/文件夹,把相应模块放在这里面。

命名空间对解决全局作用域里命名冲突来说是很重要的。 比如,你可以有一个 My.Application.Customer.AddForm和My.Application.Order.AddForm – 两个类型的名字相同,但命名空间不同。 然而,这对于模块来说却不是一个问题。 在一个模块里,没有理由两个对象拥有同一个名字。 从模块的使用角度来说,使用者会挑出他们用来引用模块的名字,所以也没有理由发生重名的情况。

更多关于模块和命名空间的资料查看命名空间和模块

10.4 危险信号

以下均为模块结构上的危险信号。重新检查以确保你没有在对模块使用命名空间:

  • 文件的顶层声明是export namespace Foo { … } (删除Foo并把所有内容向上层移动一层)
  • 文件只有一个export class或export function (考虑使用export default)
  • 多个文件的顶层具有同样的export namespace Foo { (不要以为这些会合并到一个Foo中!)

十一、13base.ts代码

// 模块 https://www.tslang.cn/docs/handbook/modules.html
// 导出声明
export interface StringValidator2 {isAcceptable(s: string): boolean;
}export const numberRegexp = /^[0-9]+$/;export class ZipCodeValidator1 implements StringValidator2 {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);}
}let zipCodeValidator = new ZipCodeValidator1()
let result = zipCodeValidator.isAcceptable("12345")
console.log(`result = ${result}`)// 导入语句
import { StringValidator } from "./Validation"
class ZipCodeValidator2 implements StringValidator {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);}
}// 导出
export { ZipCodeValidator2 };
export { ZipCodeValidator2 as mainValidator };// 重新导出
// 我们经常会去扩展其它模块,并且只导出那个模块的部分内容。 重新导出功能并不会在当前模块导入那个模块或定义一个新的局部变量。
export class ParseIntBasedZipCodeValidator2 {isAcceptable(s: string) {return s.length === 5 && parseInt(s).toString() === s;}
}// 导出原先的验证器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";// 导入
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator1 = new ZipCodeValidator();// 可以对导入内容重命名
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator2 = new ZCV();// 将整个模块导入到一个变量,并通过它来访问模块的导出部分
import * as validator3 from "./ZipCodeValidator";
let myValidator3 = new validator3.ZipCodeValidator();// 默认导出
import validator4 from "./ZipCodeValidator";
let myValidator4 = new validator4();import validate1 from "./StaticZipCodeValidator";let strings = ["Hello", "98052", "101"];// Use function validate
strings.forEach(s => {console.log(`"${s}" ${validate1(s) ? " matches" : " does not match"}`);
});// default导出也可以是一个值
import num from "./OneTwoThree";
console.log(num); // "123"// 
import zip2 = require("./ZipCodeValidator2");// Some samples to try
let strings2 = ["Hello", "98052", "101"];// Validators to use
let validator5 = new zip2();// Show whether each string passed each validator
strings2.forEach(s => {console.log(`"${ s }" - ${ validator5.isAcceptable(s) ? "matches" : "does not match" }`);
});

十二、LearnTypeScript 源码

点击查看LearnTypeScript 源码

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

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

相关文章

【C++】8.类和对象(6)

文章目录 5. 内部类6. 匿名对象7. 对象拷贝时的编译器优化 5. 内部类 如果一个类定义在另一个类的内部&#xff0c;这个内部类就叫做内部类。内部类是一个独立的类&#xff0c;跟定义在全局相比&#xff0c;他只是受外部类类域限制和访问限定符限制&#xff0c;所以外部类定义的…

QT菜单之快捷菜单设计

快捷菜单又称为上下文菜单&#xff0c;通常在用鼠标右击的时候弹出。创建快捷菜单的方法和创建菜单栏菜单类似。 效果图&#xff1a; 一、将MainWindow类对象的ContextMenuPolicy属性设置为customContextMenu。 打开mainWindow.ui&#xff0c;在属性视图上找到ContextMenuPoli…

What is the OpenAI Chat Completion API tools/functions property format?

题意&#xff1a;OpenAI 聊天完成 API 的工具/函数属性格式是什么 问题背景&#xff1a; Is there any clear documentation on the format of OpenAIs Chat Completion API tools/functions object format? I understand its JSON, but there appear to be underlying requi…

《线性代数》学渣笔记

文章目录 1 行列式1.1 克拉默法则1.2 基本性质1.3 余子式 M i j M_{ij} Mij​1.4 代数余子式 A i j ( − 1 ) i j ⋅ M i j A_{ij} (-1)^{ij} \cdot M_{ij} Aij​(−1)ij⋅Mij​1.5 具体型行列式计算&#xff08;化为基本型&#xff09;1.5.1 主对角线行列式&#xff1a;主…

数据结构实验二之线性表(下)

实验题5:实现循环双链表的各种基本运算的算法 题目描述 编写一个程序cdlinklist.cpp,实现循环双链表的各种基本运算和整体建表算法 (假设循环双链表的元素类型ElemType为int),并在此基础上设计一个程序exp2-5.cpp 完成以下功能。 (1)初始化循环双链表h。 (2)依次采用尾插法插入…

免费的 H5/PC 地图打卡 —— 功能代码及实现指南/功能代码已上传

在本文中&#xff0c;我们将通过天地图&#xff08;Tianditu&#xff09;实现一个简单的 H5/PC 版地图打卡功能。通过实时获取用户的位置&#xff0c;检测其与打卡点的距离&#xff0c;来决定是否可以完成打卡。代码已上传&#xff0c;本文将逐步介绍如何实现这一功能。 效果图…

EDI简化,两剂初免效果好

EDI简化&#xff0c;两剂初免效果好 大家好&#xff0c;疫苗是防控传染病的重要工具。但对于一些如HIV等病原体&#xff0c;有效疫苗的研发仍面临诸多挑战。在疫苗接种中&#xff0c;生发中心起着关键作用。近期研究表明——《Two-dose priming immunization amplifies humoral…

[数据集][目标检测]基于yolov5增强数据集算法mosaic来扩充自己的数据集自动生成增强图片和对应标注无需重新标注

【算法介绍】 YOLOv5最引人注目的增强技术之一是马赛克增强&#xff0c;它将四张不同的图像拼接成一张图像。 思路&#xff1a;首先&#xff0c;从数据集中随机选择四张图像&#xff0c;然后将它们缩放、随机裁剪&#xff0c;并按马赛克模式拼接在一起。这种方式允许模型看到…

为什么AI不会夺去软件工程师的工作?

▼ 自从AI大模型爆火以来&#xff0c;我每天的工作中&#xff0c;已经有大量的真实代码是通过AI完成的。人工智能辅助下的编程&#xff0c;确实大幅减轻了我的工作负担&#xff0c;大大提高了生产力。 大语言模型是如此成功&#xff0c;以至于无可避免地在开发者社区中引起了…

DesignMode__unity__抽象工厂模式在unity中的应用、用单例模式进行资源加载

目录 抽象工厂模式 思维导图 接口&#xff08;抽象类&#xff09; 工厂接口 抽象产品类 抽象武器接口 抽象人物接口 具体工厂和具体产品 具体工厂 &#xff08;1&#xff09;产品接口&#xff0c;生成具体人物 &#xff08;2&#xff09;武器接口&#xff0c;生成具体…

mapboxGL 离线部署或者说去除token最简单得方法

找到本项目中得node_modules包管理器中得mapbox-gl包 找打dist文件夹下得mapbox-gl-dev.js 相比于mapbox-gl.js得压缩文件 mapbox-gl-dev.js没有压缩&#xff0c;好修改&#xff0c;也无需要编译 在mapbox-gl-dev.js找到 this._authenticate()&#xff0c;注释或者去除即可 最…

【Proteus仿真】基于51单片机的简易电压表制作(可串口远程调控)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;设计一个简易电压表&#xff1a; 采用3位LED数码管显示被测电压值&#xff1a;基本测量范围是 0-5V&#xff1b;测量误差为士0.02V。开机或复位后&#xff0c;在 LED 最…

三角型电动采光排烟天窗的高效排烟设计优势

三角型电动采光排烟天窗的排烟效果在多个方面均展现出了显著的优势&#xff0c;主要体现在以下几个方面。一、设计原理与结构特性 三角型电动采光排烟天窗采用三角形构造&#xff0c;这种设计在结构上具有显著的稳定性&#xff0c;能够抵御不同气候条件及风压的影响。同时减少了…

网站建设合同怎么写

网站建设合同成为企业与网站开发服务提供商之间不可或缺的法律文书。一份明晰而全面的网站建设合同不仅有助于规范双方权责&#xff0c;还能有效防范潜在的合同纠纷。以下是一份网站建设合同的范本&#xff0c;旨在提供参考。 一、合同双方信息 甲方&#xff08;委托方&#x…

QT| “无法粘贴窗口部件”错误以及customplot安装使用

“无法粘贴窗口部件”错误以及customplot “无法粘贴窗口部件”错误customplot下载添加到项目中使用QCustomPlot常用的代码 “无法粘贴窗口部件”错误 情景&#xff1a;使用QT设计界面&#xff0c;很多部分比较类似&#xff0c;可以复制另一个界面的ui&#xff0c;但是粘粘的时…

TS-AI:一种用于多模态个体化脑区划分的深度学习管道,并结合任务对比合成|文献速递-Transformer架构在医学影像分析中的应用

Title 题目 TS-AI: A deep learning pipeline for multimodal subject-specific parcellation with task contrasts synthesis TS-AI&#xff1a;一种用于多模态个体化脑区划分的深度学习管道&#xff0c;并结合任务对比合成 01 文献速递介绍 人类大脑在结构和功能组织上表…

武汉正向科技 格雷母线检测方式 :车检,地检

正向科技|格雷母线原理运用-车检&#xff0c;地检 地上检测方式 地址编码器和天线箱安装在移动站上&#xff0c;通过天线箱发射地址信号&#xff0c;地址解码器安装在固定站&#xff08;地面&#xff09;上&#xff0c;在固定站完成地址检测。 车上检测方式 地址编码器安装在…

单域名、多域名、通配符SSL证书,该如何选择?

随着《网络安全法》《数据安全法》相关法律法规的发布&#xff0c;履行数据保护义务&#xff0c;做好数据安全保护是每个企业的重要工作。其中&#xff0c;SSL证书作为企业网站实现HTTPS加密保护数据传输安全的必备措施&#xff0c;根据域名保护数量&#xff0c;可以分为单域名…

拼团活动开发秘籍:PHP+Redis实现暂存成团信息,提升效率!

在用户发起成团&#xff0c;与用户入团时需要保存其成团信息&#xff08;主要是活动id与团长、团员openid&#xff09;&#xff0c;暂存在redis中&#xff0c;后期需要保存到sql中&#xff0c;以便查询。 tuan_redis.php<?php include_once(/opt/*****ub/redis.php);//red…

Java语言程序设计基础篇_编程练习题**18.35(H 树分形)

目录 题目&#xff1a;**18.35(H 树分形) 代码示例 代码解释 输出结果 题目&#xff1a;**18.35(H 树分形) 一个H 树分形(本章开始部分介绍过&#xff0c;如图18-1)如下定义: 1)从字母H开始。H的三条线长度一样&#xff0c;如图 18-1a 所示。 2)字母H(以它的 sans-serif …