詳解TypeScript中的類型斷言及其繞過類型檢查機制

TypeScript中的類型斷言及其繞過類型檢查機制

  • 一、類型斷言的本質與工作原理
    • 編譯時與運行時的區別
    • TypeScript編譯器處理類型斷言的步驟
  • 二、類型斷言的詳細語法與進階用法
    • 基礎語法對比
    • 鏈式斷言
    • 斷言修飾符
      • 1. 非空斷言操作符 (!)
        • 代碼分析
          • 1. `getLength` 函數分析
            • 用法說明:
            • 風險提示:
            • 更安全寫法(推薦):
          • 2. `getStreet` 函數分析
            • 用法說明:
            • 風險提示:
            • 更安全寫法(推薦):
          • 3. 總結
      • 2. const斷言
        • 代碼分析
          • 第一段(不使用 const 斷言)
          • 第二段(使用 const 斷言)
          • 第三段(對象字面量上的 const 斷言)
          • 總結
  • 三、類型斷言的兼容性規則詳解
    • 1. 基本兼容性規則
    • 2. 雙重斷言詳解
    • 3. 聯合類型中的類型斷言
  • 四、類型斷言與類型轉換的區別
    • 運行時的區別
  • 五、復雜場景下的類型斷言
    • 1. 斷言函數
    • 2. 使用類型謂詞定義自定義類型守衛
    • 3. 泛型與類型斷言結合
    • 4. 處理JSON解析
  • 六、類型斷言繞過類型檢查的深層機制
    • 1. 屬性檢查繞過
    • 2. 繞過只讀屬性
    • 3. 繞過函數簽名檢查
  • 七、TypeScript編譯器中的類型斷言實現
  • 八、實際項目中安全使用類型斷言的指導方針
    • 1. 謹慎使用類型斷言的場景
    • 2. 安全替代方案
      • 類型守衛
      • instanceof和typeof檢查
      • 可辨識聯合類型
    • 3. 使用斷言時的最佳實踐
  • 九、類型斷言在實際項目中的高級應用
    • 1. React組件中的類型斷言
    • 2. 處理第三方庫類型定義不完善的情況
    • 3. 混合使用斷言和類型守衛處理復雜情況
  • 總結

一、類型斷言的本質與工作原理

類型斷言在TypeScript的類型系統中扮演著特殊角色,它允許我們在編譯階段"覆蓋"TypeScript的類型推斷。從本質上講,類型斷言是一種編譯時的類型轉換指令,不會產生任何運行時代碼。

編譯時與運行時的區別

編譯前的JavaScript:

let value: any = "Hello";
let strLength = (value as string).length;

編譯后的JavaScript:

let value = "Hello";
let strLength = value.length;

可以看到,類型斷言在編譯后完全消失,不會產生任何運行時檢查代碼。

TypeScript編譯器處理類型斷言的步驟

  1. 識別斷言語法(<Type>as Type
  2. 驗證斷言是否符合類型兼容性規則
  3. 在類型檢查階段,臨時將變量視為斷言后的類型
  4. 生成JavaScript代碼時,移除所有類型斷言相關代碼

二、類型斷言的詳細語法與進階用法

基礎語法對比

// 尖括號語法
let value1: any = "Hello";
let length1 = (<string>value1).length;// as語法
let value2: any = "Hello";
let length2 = (value2 as string).length;

鏈式斷言

可以在一個表達式中連續使用多次斷言:

const element = document.getElementById('myButton') as HTMLElement as HTMLButtonElement;

斷言修飾符

1. 非空斷言操作符 (!)

用于告訴TypeScript某個值不會是nullundefined

function getLength(str: string | null) {// 非空斷言運算符return str!.length; // 告訴TS編譯器str一定不是null
}// 在可選鏈中使用
type User = { address?: { street?: string } };
function getStreet(user: User) {// 非空斷言與可選鏈結合return user.address!.street!; // 危險用法,建議避免
}
代碼分析
1. getLength 函數分析
function getLength(str: string | null) {return str!.length;
}
用法說明:
  • 參數 str 的類型是 string | null,意味著它可能是字符串,也可能是 null
  • 使用 str! 表示 非空斷言 —— 告訴 TypeScript 編譯器:“我確定這里的 str 不是 null 或 undefined”
  • str!.length:直接取 str.length
風險提示:
  • 如果調用該函數時傳入了 null,仍會運行時拋出錯誤:
    getLength(null); // 會拋出 TypeError: Cannot read property 'length' of null
    
更安全寫法(推薦):
function getLengthSafe(str: string | null) {return str?.length ?? 0; // 如果是 null,則返回 0
}
2. getStreet 函數分析
type User = { address?: { street?: string } };function getStreet(user: User) {return user.address!.street!;
}
用法說明:
  • user.address!:強制斷言 address 存在。
  • street!:再斷言 street 也存在。
  • 整個表達式假定:user.addressuser.address.street一定不是 undefined 或 null
風險提示:
  • user.addressstreet 實際上不存在,這種寫法將導致運行時錯誤。
  • 非空斷言 + 可選屬性 是一種危險組合,違背了可選鏈的初衷。
更安全寫法(推薦):
function getStreetSafe(user: User) {return user.address?.street ?? '未知街道';
}
3. 總結
非空斷言運算符 !可選鏈操作符 ?.
告訴編譯器“這肯定不是 null/undefined”只有在值不為 null/undefined 時才繼續訪問
編譯器通過,但運行時有風險編譯和運行都更安全
應謹慎使用更推薦

2. const斷言

將表達式標記為完全不可變的字面量類型:

// 不使用const斷言
const colors = ["red", "green", "blue"]; // 類型是string[]// 使用const斷言
const colorsConst = ["red", "green", "blue"] as const; // 類型是readonly ["red", "green", "blue"]// 對象字面量的const斷言
const point = { x: 10, y: 20 } as const; // 所有屬性變為readonly
代碼分析

這段 TypeScript 代碼的核心目的是對比使用 const 斷言與不使用 const 斷言時變量類型的差異,特別是在數組和對象字面量上的表現。

第一段(不使用 const 斷言)
const colors = ["red", "green", "blue"]; // 類型是 string[]
  • colors 是一個數組,推斷類型為 string[]
  • 這意味著:
    • 數組可以被修改(如 push)。
    • 數組中的元素類型是 string,但不限定具體值。
第二段(使用 const 斷言)
const colorsConst = ["red", "green", "blue"] as const;
  • as const 會使整個數組成為 只讀的元組類型
    • 類型為 readonly ["red", "green", "blue"]
    • 每個元素都是 字符串字面量類型(即 "red""green""blue"),不是 string。
    • 無法修改數組結構或其元素。
第三段(對象字面量上的 const 斷言)
const point = { x: 10, y: 20 } as const;
  • point 的類型為 readonly { x: 10; y: 20 }
  • 整個對象及其屬性都被推斷為只讀,并且值為字面量類型。
  • 不可再對 point.xpoint.y 賦新值。
總結
斷言方式類型推斷可否修改
無 const 斷言一般類型(如 string[], { x: number })可修改
使用 as const字面量類型 + readonly 修飾不可修改(只讀)

三、類型斷言的兼容性規則詳解

TypeScript對類型斷言有嚴格的兼容性規則:

1. 基本兼容性規則

  • 源類型是目標類型的子類型,或
  • 目標類型是源類型的子類型
// 合法: string是Object的子類型
let str = "hello" as Object;// 合法: HTMLDivElement是HTMLElement的子類型
let element = document.createElement('div') as HTMLDivElement;// 不合法: number與string既不是子類型關系
// let num = 42 as string; // 錯誤

2. 雙重斷言詳解

當直接斷言不符合兼容性規則時,需要通過unknownany作為中間類型:

// 這兩種類型完全不兼容
interface Dog { bark(): void; }
interface Cat { meow(): void; }let dog: Dog = { bark: () => console.log('Woof!') };// 錯誤: Dog和Cat沒有子類型關系
// let cat = dog as Cat;// 正確: 通過unknown作為中間類型
let cat1 = dog as unknown as Cat;// 或者使用any
let cat2 = dog as any as Cat;

3. 聯合類型中的類型斷言

在聯合類型中斷言為其中一個具體類型時,類型兼容性自動滿足:

function processValue(value: string | number) {// 合法的斷言 - value可能是stringif ((value as string).toUpperCase) {console.log((value as string).toUpperCase());} else {console.log((value as number).toFixed(2));}
}

四、類型斷言與類型轉換的區別

TypeScript中的類型斷言與JavaScript中的類型轉換概念完全不同:

// 類型斷言 - 僅編譯時存在
const value: any = "42";
const strValue = value as string; // 不會改變值的類型// 類型轉換 - 運行時操作
const numValue = Number(value); // 實際將字符串轉為數字

運行時的區別

let str: any = "42";// 類型斷言 - 運行時不執行實際轉換
let num1 = str as number;
console.log(typeof num1); // 輸出: "string"// 類型轉換 - 運行時實際轉換
let num2 = Number(str);
console.log(typeof num2); // 輸出: "number"

五、復雜場景下的類型斷言

1. 斷言函數

TypeScript 3.7+引入了斷言函數,可以使用函數進行類型保護:

function assertIsString(val: any): asserts val is string {if (typeof val !== "string") {throw new Error("Value is not a string");}
}function processValue(value: unknown) {assertIsString(value);// 這里value已經被斷言為string類型console.log(value.toUpperCase());
}

2. 使用類型謂詞定義自定義類型守衛

interface Bird {fly(): void;layEggs(): void;
}interface Fish {swim(): void;layEggs(): void;
}// 類型謂詞: pet is Fish
function isFish(pet: Fish | Bird): pet is Fish {return (pet as Fish).swim !== undefined;
}function moveAnimal(pet: Fish | Bird) {if (isFish(pet)) {// 在這個塊中,TypeScript知道pet是Fishpet.swim();} else {// 在這個塊中,TypeScript知道pet是Birdpet.fly();}
}

3. 泛型與類型斷言結合

function convertValue<T, U>(value: T, toType: (v: T) => U): U {return toType(value);
}// 使用類型斷言處理泛型
function identity<T>(value: unknown): T {return value as T;
}const str = identity<string>("hello"); // 類型為string

4. 處理JSON解析

interface User {id: number;name: string;email: string;
}// 從API獲取JSON數據
async function fetchUser(id: number): Promise<User> {const response = await fetch(`/api/users/${id}`);const data = await response.json();// 使用類型斷言處理未知JSON結構return data as User;
}// 更安全的做法是添加驗證
function isUser(obj: any): obj is User {return (typeof obj === 'object' &&typeof obj.id === 'number' &&typeof obj.name === 'string' &&typeof obj.email === 'string');
}async function fetchUserSafe(id: number): Promise<User> {const response = await fetch(`/api/users/${id}`);const data = await response.json();if (isUser(data)) {return data;}throw new Error('Invalid user data');
}

六、類型斷言繞過類型檢查的深層機制

1. 屬性檢查繞過

interface RequiredProps {id: number;name: string;age: number;email: string;
}// 屬性過多或過少都會報錯
const userWithMissingProps: RequiredProps = {id: 1,name: "張三"// 缺少age和email屬性
} as RequiredProps; // 繞過了缺少屬性的檢查const userWithExtraProps = {id: 1,name: "張三",age: 30,email: "zhangsan@example.com",extraProp: "額外屬性" // 多余屬性
} as RequiredProps; // 繞過了多余屬性的檢查

2. 繞過只讀屬性

interface ReadOnlyUser {readonly id: number;readonly name: string;
}function updateUser(user: ReadOnlyUser) {// 使用類型斷言繞過只讀限制(user as { id: number }).id = 100; // 危險操作!
}

3. 繞過函數簽名檢查

type SafeFunction = (a: number, b: number) => number;
type UnsafeFunction = (a: any, b: any) => any;// 假設有一個不安全的函數
const unsafeAdd: UnsafeFunction = (a, b) => {return a + b; // 可能產生意外結果,如字符串拼接
};// 使用斷言強制轉換函數類型
const safeAdd = unsafeAdd as SafeFunction;// TypeScript不會檢查實際實現是否符合SafeFunction的要求
safeAdd("hello", "world"); // 在編譯時看起來安全,但運行時會拼接字符串

七、TypeScript編譯器中的類型斷言實現

從編譯器角度看,類型斷言的處理方式:

  1. 類型檢查階段:當編譯器遇到類型斷言時,它會暫時忽略變量的實際類型,而使用斷言指定的類型進行后續檢查。

  2. 代碼生成階段:斷言相關的所有信息都會被移除,不會生成任何額外的JavaScript代碼。

  3. 類型擦除:和所有TypeScript類型信息一樣,類型斷言在編譯結束后完全消失。


八、實際項目中安全使用類型斷言的指導方針

1. 謹慎使用類型斷言的場景

  • 處理第三方庫返回的any類型
  • 處理DOM API返回的通用類型
  • 在確信比TypeScript更了解類型時
  • 進行類型細化(Narrowing)
  • 實現遺留代碼的漸進式類型化

2. 安全替代方案

類型守衛

type Shape = | { kind: 'circle'; radius: number }| { kind: 'rectangle'; width: number; height: number }| { kind: 'triangle'; base: number; height: number };// 使用類型守衛代替類型斷言
function isCircle(shape: Shape): shape is { kind: 'circle'; radius: number } {return shape.kind === 'circle';
}function isRectangle(shape: Shape): shape is { kind: 'rectangle'; width: number; height: number } {return shape.kind === 'rectangle';
}function calculateArea(shape: Shape): number {if (isCircle(shape)) {// 這里shape被細化為圓形類型return Math.PI * shape.radius ** 2;} else if (isRectangle(shape)) {// 這里shape被細化為矩形類型return shape.width * shape.height;} else {// TypeScript知道這里是三角形return 0.5 * shape.base * shape.height;}
}

上述代碼通過 TypeScript 定義了一個表示幾何形狀的類型 Shape,其中包含圓形(circle)、矩形(rectangle)和三角形(triangle)三種類型。

為實現類型安全的面積計算,代碼還定義了兩個類型守衛函數 isCircleisRectangle

calculateArea 函數中,通過類型守衛對輸入的 shape 參數進行檢查:

  1. 如果是圓形,使用圓面積公式 πr2 計算面積;
  2. 如果是矩形,使用矩形面積公式 長×寬 計算面積;
  3. 在其他情況下(根據類型定義只能是三角形),使用三角形面積公式 ?×底×高 計算面積。

通過使用類型守衛,代碼實現了在編譯階段就能確定不同形狀的類型信息,從而避免了類型斷言可能帶來的運行時錯誤,提高了代碼的安全性。

instanceof和typeof檢查

function processValue(value: unknown) {// 使用typeof代替斷言if (typeof value === 'string') {console.log(value.toUpperCase());} // 使用instanceof代替斷言else if (value instanceof Date) {console.log(value.toISOString());}
}

上述代碼通過 TypeScript 的 typeofinstanceof 操作符替代了類型斷言,用來處理未知類型的值(unknown)。

函數 processValue 首先檢查參數 value 是否為字符串,如果是則將其轉換為大寫并輸出;否則檢查是否為 Date 實例,如果是則輸出其 ISO 格式字符串。

這種類型檢查方式比直接斷言類型更安全,因為它們在運行時驗證了值的真實類型,從而避免了潛在的運行時錯誤。

可辨識聯合類型

interface SuccessResponse {status: 'success';data: { id: number; name: string };
}interface ErrorResponse {status: 'error';error: { code: number; message: string };
}type ApiResponse = SuccessResponse | ErrorResponse;// 不使用斷言,而是利用可辨識屬性
function handleResponse(response: ApiResponse) {if (response.status === 'success') {// 在這個塊中,TypeScript知道response是SuccessResponseconsole.log(response.data.name);} else {// 在這個塊中,TypeScript知道response是ErrorResponseconsole.log(response.error.message);}
}

這段代碼使用 TypeScript 的聯合類型(ApiResponseSuccessResponseErrorResponse 的聯合)和可辨識屬性(status)。

在函數 handleResponse 中,通過檢查 response.status 的值,TypeScript 能自動細化類型:

  • status === 'success' 時,response 被識別為 SuccessResponse,從而可以安全地訪問 response.data.name
  • status !== 'success'(即 status === 'error'),response 被識別為 ErrorResponse,從而可以安全地訪問 response.error.message

3. 使用斷言時的最佳實踐

// 1. 添加詳細注釋說明斷言原因
/* * 由于這個DOM元素在HTML中是通過ID "searchInput" 創建的input元素,* 因此我們可以安全地將其斷言為HTMLInputElement*/
const searchInput = document.getElementById('searchInput') as HTMLInputElement;// 2. 考慮添加運行時驗證
function processUserData(data: unknown) {// 類型斷言前添加運行時檢查if (typeof data === 'object' && data !== null && 'name' in data && 'age' in data) {// 斷言更安全const user = data as { name: string; age: number };console.log(user.name, user.age);}
}// 3. 創建驗證函數
function validateUser(data: any): data is User {return (typeof data === 'object' &&data !== null &&typeof data.id === 'number' &&typeof data.name === 'string');
}function processUser(data: unknown) {if (validateUser(data)) {// 不需要斷言,類型已經被守衛函數細化console.log(data.id, data.name);}
}

九、類型斷言在實際項目中的高級應用

1. React組件中的類型斷言

import React, { useRef } from 'react';function VideoPlayer() {// 使用泛型和斷言結合const videoRef = useRef<HTMLVideoElement>(null);const playVideo = () => {// 非空斷言在確定元素存在時使用videoRef.current!.play();// 或者更安全的方式if (videoRef.current) {videoRef.current.play();}};return (<div><video ref={videoRef} src="/video.mp4" /><button onClick={playVideo}>播放</button></div>);
}

2. 處理第三方庫類型定義不完善的情況

// 假設有一個第三方庫沒有正確定義返回類型
import { fetchData } from 'third-party-library';interface User {id: number;name: string;email: string;
}async function getUser(id: number): Promise<User> {// 第三方庫返回anyconst data = await fetchData(`/users/${id}`);// 添加運行時驗證后進行斷言if (typeof data === 'object' &&data !== null &&typeof data.id === 'number' &&typeof data.name === 'string' &&typeof data.email === 'string') {return data as User;}throw new Error('Invalid user data');
}

3. 混合使用斷言和類型守衛處理復雜情況

type DataItem = {id: number;value: string | number | boolean | object;metadata?: Record<string, unknown>;
};function processDataItem(item: DataItem) {// 針對不同類型值的處理if (typeof item.value === 'string') {console.log(item.value.toUpperCase());} else if (typeof item.value === 'number') {console.log(item.value.toFixed(2));}else if (typeof item.value === 'object') {// 這里可能需要進一步細化對象類型if (Array.isArray(item.value)) {// 斷言為數組類型const array = item.value as unknown[];console.log(array.length);} else {// 斷言為普通對象const obj = item.value as Record<string, unknown>;console.log(Object.keys(obj));}}// 處理可選的metadataif (item.metadata) {// 特定情況下可能知道某些metadata字段的存在if ('timestamp' in item.metadata) {const timestamp = item.metadata.timestamp as number;console.log(new Date(timestamp));}}
}

總結

類型斷言是TypeScript中一個強大但需謹慎使用的特性。它提供了在靜態類型檢查系統中的"逃生艙",讓開發者能夠處理復雜或特殊情況。但過度依賴類型斷言會削弱TypeScript的類型安全優勢,增加運行時錯誤的風險。

最佳實踐是:

  1. 優先使用類型守衛、可辨識聯合類型等類型安全的方法
  2. 在使用類型斷言時添加運行時驗證
  3. 創建自定義的類型守衛函數代替簡單斷言
  4. 清晰注釋說明為什么需要類型斷言
  5. 定期審查代碼庫中的類型斷言,尋找更類型安全的替代方案

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81250.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81250.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81250.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

XLSX.utils.sheet_to_json設置了blankrows:true,但無法獲取到開頭的空白行

在用sheetJs的XLSX庫做導入&#xff0c;遇到一個bug。如果開頭行是空白行的話&#xff0c;調用sheet_to_json轉數組獲得的數據也是沒有包含空白行的。這樣會導致在設置對應的起始行時&#xff0c;解析數據不生效。 目前是直接跳過了開頭的兩行空白行 正確應該獲得一下數據 問…

PostgreSQL 數據庫下載和安裝

官網&#xff1a; PostgreSQL: Downloads 推薦下載網站&#xff1a;EDB downloads postgresql 我選了 postgresql-15.12-1-windows-x64.exe 鼠標雙擊&#xff0c;開始安裝&#xff1a; 安裝路徑&#xff1a; Installation Directory: D:\Program Files\PostgreSQL\15 Serv…

一、Javaweb是什么?

1.1 客戶端與服務端 客戶端 &#xff1a;用于與用戶進行交互&#xff0c;接受用戶的輸入或操作&#xff0c;且展示服務器端的數據以及向服務器傳遞數據。 例如&#xff1a;手機app&#xff0c;微信小程序、瀏覽器… 服務端 &#xff1a;與客戶端進行交互&#xff0c;接受客戶…

奇偶ASCII值判斷

奇偶ASCII值判斷 Description 任意輸入一個字符&#xff0c;判斷其ASCII是否是奇數&#xff0c;若是&#xff0c;輸出YES&#xff0c;否則&#xff0c;輸出NO。例如&#xff0c;字符A的ASCII值是65&#xff0c;則輸出YES&#xff0c;若輸入字符B(ASCII值是66)&#xff0c;則輸…

OpenCV 圖形API(74)圖像與通道拼接函數-----合并三個單通道圖像(GMat)為一個多通道圖像的函數merge3()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 從3個單通道矩陣創建一個3通道矩陣。 此函數將多個矩陣合并以生成一個單一的多通道矩陣。即&#xff0c;輸出矩陣的每個元素將是輸入矩陣元素的…

多節點監測任務分配方法比較與分析

多監測節點任務分配方法是分布式系統、物聯網&#xff08;IoT&#xff09;、工業監測等領域的核心技術&#xff0c;其核心目標是在資源受限條件下高效分配任務&#xff0c;以優化系統性能。以下從方法分類、對比分析、應用場景選擇及挑戰等方面進行系統闡述&#xff1a; 圖1 多…

【推薦系統筆記】BPR損失函數公式

一、BPR損失函數公式 BPR 損失函數的核心公式如下&#xff1a; L BPR ? ∑ ( u , i , j ) ∈ D ln ? σ ( x ^ u i j ) λ ∣ ∣ Θ ∣ ∣ 2 L_{\text{BPR}} - \sum_{(u, i, j) \in D} \ln \sigma(\hat{x}_{uij}) \lambda ||\Theta||^2 LBPR??(u,i,j)∈D∑?lnσ(x^ui…

Java 核心--泛型枚舉

作者&#xff1a;IvanCodes 發布時間&#xff1a;2025年4月30日&#x1f913; 專欄&#xff1a;Java教程 各位 CSDN伙伴們&#xff0c;大家好&#xff01;&#x1f44b; 寫了那么多代碼&#xff0c;有沒有遇到過這樣的“驚喜”&#xff1a;滿心歡喜地從 ArrayList 里取出數據…

新能源行業供應鏈規劃及集成計劃報告(95頁PPT)(文末有下載方式)

資料解讀&#xff1a;《數字化供應鏈規劃及集成計劃現狀評估報告》 詳細資料請看本解讀文章的最后內容。 該報告圍繞新能源行業 XX 企業供應鏈展開&#xff0c;全面評估其現狀&#xff0c;剖析存在的問題&#xff0c;并提出改進方向和關鍵舉措&#xff0c;旨在提升供應鏈競爭力…

Centos 7 yum配置出現一下報錯:

One of the configured repositories failed (CentOS-$releaserver-Base), and yum doesnt have enough cached data to continue. At this point the only safe thing yum can do is fail. There are a few ways to work "fix" this: 1.解決CentOS Yum Repositor…

Redis 常見問題深度剖析與全方位解決方案指南

Redis 是一款廣泛使用的開源內存數據庫&#xff0c;在實際應用中常會遇到以下一些常見問題&#xff1a; 1.內存占用問題 問題描述&#xff1a;隨著數據量的不斷增加&#xff0c;Redis 占用的內存可能會超出預期&#xff0c;導致服務器內存不足&#xff0c;影響系統的穩定性和…

HOOK上癮思維模型——AI與思維模型【88】

一、定義 HOOK上癮思維模型是一種通過設計一系列的觸發&#xff08;Trigger&#xff09;、行動&#xff08;Action&#xff09;、獎勵&#xff08;Reward&#xff09;和投入&#xff08;Investment&#xff09;環節&#xff0c;來促使用戶形成習慣并持續使用產品或服務的思維框…

【playwright】內網離線部署playwright

背景&#xff1a;安裝好python3.9后&#xff0c;由于內網無法使用pip安裝playwright&#xff0c;多方收集資料&#xff0c;終于部署完成&#xff0c;現匯總如下&#xff1a; 1、playwright需要python3.7以上的版本&#xff0c;如果低于這個版本先要將python解釋器升級 2、在可…

Unity動態列表+UniTask異步數據請求

Unity動態列表UniTask異步數據請求 很久沒有寫東西了。最近有一個需求&#xff0c;在Unity項目里&#xff0c;有幾個比較長的列表&#xff0c;經歷了一翻優化&#xff0c;趁這幾日閑暇&#xff0c;記錄下來&#xff0c;給自己留個筆記&#xff0c;也送給有緣之人共同探討吧。 …

pandas讀取Excel數據(.xlsx和.xls)到treeview

對于.xls文件&#xff0c;xlrd可能更合適&#xff0c;但需要注意新版本的xlrd可能不支持xlsx&#xff0c;不過用戶可能同時需要處理兩種格式&#xff0c;所以可能需要結合openpyxl和xlrd&#xff1f;或者直接用pandas&#xff0c;因為它內部會處理這些依賴。 然后&#xff0c;…

2025年Jetpack Compose集成網絡請求庫的完整實施方案

Compose中集成網絡請求庫&#xff0c;網絡請求現在Retrofit是最流行的。 首先在Compose中如何進行網絡請求&#xff0c;而不僅僅是集成庫。因為Compose本身是UI框架&#xff0c;網絡請求其實還是通過ViewModel或者Repository來處理&#xff0c;然后通過狀態管理來更新UI。所以…

機器視覺開發-攝像頭掃描二維碼

以下是使用Python和OpenCV實現攝像頭掃描二維碼的最簡單示例&#xff1a; import cv2 from pyzbar import pyzbar# 打開攝像頭 cap cv2.VideoCapture(0)print("正在掃描二維碼... (按 q 鍵退出)")while True:# 讀取攝像頭幀ret, frame cap.read()if not ret:print…

Seata服務端回滾事務核心源碼解析

文章目錄 前言一、doGlobalRollback3.1、changeGlobalStatus3.2、doGlobalRollback 前言 本篇介紹Seata服務端接收到客戶端TM回滾請求&#xff0c;進行處理并且驅動所有的RM進行回滾的源碼。 一、doGlobalRollback doGlobalRollback是全局回滾的方法&#xff1a; ??首先依舊…

新聞客戶端案例的實現,使用axios獲取數據并渲染頁面,路由傳參(查詢參數,動態路由),使用keep-alive實現組件緩存

文章目錄 0.頁面要求1.功能要求2.開始路由配置2.1.嵌套二級路由如何配置?2.2.路由重定向,NotFound頁面,去除"#"號 3.實現底部導航欄的高亮效果4.渲染首頁:使用axios請求數據5.路由傳參5.1.回顧:查詢參數傳參或者動態路由傳參5.2.具體代碼 6.渲染詳情頁7.解決請求過程…

文件操作--文件包含漏洞

本文主要內容 腳本 ASP、PHP、JSP、ASPX、Python、Javaweb --# 各種包含函數 檢測 白盒 代碼審計 黑盒 漏掃工具、公開漏洞、手工看參數值及功能點 類型 本地包含 有限制、無限制 遠程包含 無限制、有限制…