React 更新 state 中的数组

news2025/7/14 11:46:01

更新 state 中的数组

数组是另外一种可以存储在 state 中的 JavaScript 对象,它虽然是可变的,但是却应该被视为不可变。同对象一样,当你想要更新存储于 state 中的数组时,你需要创建一个新的数组(或者创建一份已有数组的拷贝值),并使用新数组设置 state。

开发环境:React+ts+antd
文中例子参考React官方文档教程,不同的是这里使用TypeScript 来写

学习内容

  • 如何添加、删除或者修改 React state 中的数组中的元素
  • 如何更新数组内部的对象
  • 如何通过 Immer 降低数组拷贝的重复度

在没有 mutation 的前提下更新数组

在 JavaScript 中,数组只是另一种对象。同对象一样,你需要将 React state 中的数组视为只读的。这意味着你不应该使用类似于 arr[0] = ‘bird’ 这样的方式来重新分配数组中的元素,也不应该使用会直接修改原始数组的方法,例如 push() 和 pop()。

相反,每次要更新一个数组时,你需要把一个新的数组传入 state 的 setting 方法中。为此,你可以通过使用像 filter() 和 map() 这样不会直接修改原始值的方法,从原始数组生成一个新的数组。然后你就可以将 state 设置为这个新生成的数组。

下面是常见数组操作的参考表。当你操作 React state 中的数组时,你需要避免使用左列的方法,而首选右列的方法:

避免使用 (会改变原始数组)推荐使用 (会返回一个新数组)
添加元素push,unshiftconcat,[…arr] 展开语法
删除元素pop,shift,splicefilter,slice
替换元素splice,arr[i] = … 赋值map
排序reverse,sort先将数组复制一份

或者,你可以使用 Immer ,这样你便可以使用表格中的所有方法了。

向数组中添加元素

创建一个 数组,其包含了原始数组的所有元素 以及 一个在末尾的新元素。这可以通过很多种方法实现,最简单的一种就是使用 … 数组展开 语法:

setArtists( // 替换 state
  [ // 是通过传入一个新数组实现的
    ...artists, // 新数组包含原数组的所有元素
    { id: nextId++, name: name } // 并在末尾添加了一个新的元素
  ]
);

例子

import React from 'react';
import { useState } from 'react';
import { Input, Button } from 'antd';
// 定义 Artist 类型
type Artist = {
    id: number;
    name: string;
};
const App: React.FC = () => {
    let nextId = 0;
    const [name, setName] = useState<string>('');
    const [artists, setArtists] = useState<Artist[]>([]);
    return (
        <>
            <h1>添加列表:</h1>
            <Input
                style={{ width: '200px', marginRight: '10px' }}
                value={name}
                onChange={e => setName(e.target.value)}
            />
            <Button
                color="blue"
                variant="solid"
                onClick={() => {
                setArtists([
                    ...artists,
                    {id: nextId++, name: name}
                ]);
            }}>添加</Button>
            <ul>
                {artists.map(artist => (
                    <li key={artist.id}>{artist.name}</li>
                ))}
            </ul>
        </>
    );
};

export default App;

在这里插入图片描述
数组展开运算符还允许你把新添加的元素放在原始的 …artists 之前:

setArtists([
  { id: nextId++, name: name },
  ...artists // 将原数组中的元素放在末尾
]);

这样一来,展开操作就可以完成 push() 和 unshift() 的工作,将新元素添加到数组的末尾和开头。

从数组中删除元素

从数组中删除一个元素最简单的方法就是将它过滤出去。换句话说,你需要生成一个不包含该元素的新数组。这可以通过 filter 方法实现,例如:

import React from 'react';
import { useState } from 'react';
let initialArtists = [
    { id: 0, name: 'Marta Colvin Andrade' },
    { id: 1, name: 'Lamidi Olonade Fakeye'},
    { id: 2, name: 'Louise Nevelson'},
];
const App: React.FC = () => {
    const [artists, setArtists] = useState(
        initialArtists
    );
    return (
        <>
            <h1>删除列表:</h1>
            <ul>
                {artists.map(artist => (
                    <li key={artist.id}>
                        {artist.name}{' '}
                        <button onClick={() => {
                            setArtists(
                                artists.filter(a =>
                                    a.id !== artist.id
                                )
                            );
                        }}>
                            删除
                        </button>
                    </li>
                ))}
            </ul>
        </>
    );
};

export default App;

在这里插入图片描述
点击“删除”按钮几次,并且查看按钮处理点击事件的代码。

setArtists(
  artists.filter(a => a.id !== artist.id)
);

这里,artists.filter(s => s.id !== artist.id) 表示“创建一个新的数组,该数组由那些 ID 与 artists.id 不同的 artists 组成”。换句话说,每个 artist 的“删除”按钮会把 那一个 artist 从原始数组中过滤掉,并使用过滤后的数组再次进行渲染。

注意,filter 并不会改变原始数组

转换数组

如果你想改变数组中的某些或全部元素,你可以用 map() 创建一个新数组。你传入 map 的函数决定了要根据每个元素的值或索引(或二者都要)对元素做何处理。

在下面的例子中,一个数组记录了两个圆形和一个正方形的坐标。当你点击按钮时,仅有两个圆形会向下移动 50 像素。这是通过使用 map() 生成一个新数组实现的。

import React from 'react';
import { useState } from 'react';
import {Button} from "antd";

let initialShapes = [
    { id: 0, type: 'circle', x: 0, y: 100 },
    { id: 1, type: 'square', x: 100, y: 100 },
    { id: 2, type: 'circle', x: 200, y: 100 },
];
const App: React.FC = () => {
    const [shapes, setShapes] = useState(
        initialShapes
    );
    const handleClick=()=> {
        const nextShapes = shapes.map(shape => {
            if (shape.type === 'square') {
                // 不作改变
                return shape;
            } else {
                // 返回一个新的圆形,位置在下方 50px 处
                return {
                    ...shape,
                    y: shape.y + 50,
                };
            }
        });
        // 使用新的数组进行重渲染
        setShapes(nextShapes);
    }
    return (
        <>
            <Button type='primary' onClick={handleClick}>
                所有圆形向下移动!
            </Button>
            <div style={{position:"relative"}}>
                {shapes.map(shape => (
                    <div
                        key={shape.id}
                        style={{
                            background: 'purple',
                            position: 'absolute',
                            left: shape.x,
                            top: shape.y,
                            borderRadius:
                                shape.type === 'circle'
                                    ? '50%' : '',
                            width: 20,
                            height: 20,
                        }} />
                ))}
            </div>
        </>
    );
};

export default App;

在这里插入图片描述

点击按钮后:
在这里插入图片描述

替换数组中的元素

想要替换数组中一个或多个元素是非常常见的。类似 arr[0] = ‘bird’ 这样的赋值语句会直接修改原始数组,所以在这种情况下,你也应该使用 map。

要替换一个元素,请使用 map 创建一个新数组。在你的 map 回调里,第二个参数是元素的索引。使用索引来判断最终是返回原始的元素(即回调的第一个参数)还是替换成其他值:

import React from 'react';
import { useState } from 'react';
import {Button} from "antd";

let initialCounters = [
    0, 0, 0
];
const App: React.FC = () => {
    const [counters, setCounters] = useState(
        initialCounters
    );
    const handleIncrementClick=(index:number)=> {
        const nextCounters = counters.map((c, i) => {
            if (i === index) {
                // 递增被点击的计数器数值
                return c + 1;
            } else {
                // 其余部分不发生变化
                return c;
            }
        });
        setCounters(nextCounters);
    }
    return (
        <>
            <ul>
                {counters.map((counter, i) => (
                    <li key={i} style={{marginBottom:"20px"}}>
                        <span style={{marginRight:"20px"}}>{counter}</span>
                        <Button type="primary" onClick={() => {
                            handleIncrementClick(i);
                        }}>+1
                        </Button>
                    </li>
                ))}
            </ul>
        </>
    );
};

export default App;

在这里插入图片描述

向数组中插入元素

有时,你也许想向数组特定位置插入一个元素,这个位置既不在数组开头,也不在末尾。为此,你可以将数组展开运算符 … 和 slice() 方法一起使用。slice() 方法让你从数组中切出“一片”。为了将元素插入数组,你需要先展开原数组在插入点之前的切片,然后插入新元素,最后展开原数组中剩下的部分。

下面的例子中,插入按钮总是会将元素插入到数组中索引为 1 的位置。

import React from 'react';
import { useState } from 'react';
import {Button,Input} from "antd";

let nextId = 3;
const initialArtists = [
    { id: 0, name: '清明上河图密码' },
    { id: 1, name: '雪迷宫'},
    { id: 2, name: '白夜行'},
];
const App: React.FC = () => {
    const [name, setName] = useState('');
    const [artists, setArtists] = useState(
        initialArtists
    );
    const handleClick=()=> {
        const insertAt = 1; // 可能是任何索引
        const nextArtists = [
            // 插入点之前的元素:
            ...artists.slice(0, insertAt),
            // 新的元素:
            { id: nextId++, name: name },
            // 插入点之后的元素:
            ...artists.slice(insertAt)
        ];
        setArtists(nextArtists);
        setName('');
    }
    return (
        <>
            <h1>添加列表:</h1>
            <Input
                style={{width:"200px",marginRight:"10px"}}
                value={name}
                onChange={e => setName(e.target.value)}
            />
            <Button type="primary" onClick={handleClick}>
                插入
            </Button>
            <ul>
                {artists.map(artist => (
                    <li key={artist.id}>{artist.name}</li>
                ))}
            </ul>
        </>
    );
};

export default App;

在这里插入图片描述

其他改变数组的情况

总会有一些事,是你仅仅依靠展开运算符和 map() 或者 filter() 等不会直接修改原值的方法所无法做到的。例如,你可能想翻转数组,或是对数组排序。而 JavaScript 中的 reverse() 和 sort() 方法会改变原数组,所以你无法直接使用它们。

然而,你可以先拷贝这个数组,再改变这个拷贝后的值。

例如:

import React from 'react';
import { useState } from 'react';
import {Button} from "antd";

const initialList = [
    { id: 0, title: 'Big Bellies' },
    { id: 1, title: 'Lunar Landscape' },
    { id: 2, title: 'Terracotta Army' },
];
const App: React.FC = () => {
    const [list, setList] = useState(initialList);

    const handleClick=()=> {
        const nextList = [...list];
        nextList.reverse();
        setList(nextList);
    }
    return (
        <>
            <Button type="primary" onClick={handleClick}>
                翻转
            </Button>
            <ul>
                {list.map(artwork => (
                    <li key={artwork.id}>{artwork.title}</li>
                ))}
            </ul>
        </>
    );
};

export default App;

在这里插入图片描述

点击翻转后

在这里插入图片描述
在这段代码中,你先使用 […list] 展开运算符创建了一份数组的拷贝值。当你有了这个拷贝值后,你就可以使用像 nextList.reverse() 或 nextList.sort() 这样直接修改原数组的方法。你甚至可以通过 nextList[0] = “something” 这样的方式对数组中的特定元素进行赋值。

然而,即使你拷贝了数组,你还是不能直接修改其内部的元素。这是因为数组的拷贝是浅拷贝——新的数组中依然保留了与原始数组相同的元素。因此,如果你修改了拷贝数组内部的某个对象,其实你正在直接修改当前的 state。举个例子,像下面的代码就会带来问题。

const nextList = [...list];
nextList[0].seen = true; // 问题:直接修改了 list[0] 的值
setList(nextList);

虽然 nextList 和 list 是两个不同的数组,nextList[0] 和 list[0] 却指向了同一个对象。因此,通过改变 nextList[0].seen,list[0].seen 的值也被改变了。这是一种 state 的 mutation 操作,你应该避免这么做!你可以用类似于 更新嵌套的 JavaScript 对象 的方式解决这个问题——拷贝想要修改的特定元素,而不是直接修改它。下面是具体的操作。

更新数组内部的对象

对象并不是 真的 位于数组“内部”。可能他们在代码中看起来像是在数组“内部”,但其实数组中的每个对象都是这个数组“指向”的一个存储于其它位置的值。这就是当你在处理类似 list[0] 这样的嵌套字段时需要格外小心的原因。其他人的艺术品清单可能指向了数组的同一个元素!

当你更新一个嵌套的 state 时,你需要从想要更新的地方创建拷贝值,一直这样,直到顶层。 让我们看一下这该怎么做。

在下面的例子中,两个不同的艺术品清单有着相同的初始 state。他们本应该互不影响,但是因为一次 mutation,他们的 state 被意外地共享了,勾选一个清单中的事项会影响另外一个清单:

import React, { useState } from 'react';

// 定义 Artwork 类型
type Artwork = {
    id: number;
    title: string;
    seen: boolean;
};

// 定义初始列表
const initialList: Artwork[] = [
    { id: 0, title: 'Big Bellies', seen: false },
    { id: 1, title: 'Lunar Landscape', seen: false },
    { id: 2, title: 'Terracotta Army', seen: true },
];

// 定义 App 组件
const App: React.FC = () => {
    const [myList, setMyList] = useState<Artwork[]>(initialList);
    const [yourList, setYourList] = useState<Artwork[]>(initialList);

    const handleToggleMyList = (artworkId: number, nextSeen: boolean) => {
        const myNextList = [...myList];
        const artwork = myNextList.find(a => a.id === artworkId);
        if (artwork) {
            artwork.seen = nextSeen;
            setMyList(myNextList);
        }
    };

    const handleToggleYourList = (artworkId: number, nextSeen: boolean) => {
        const yourNextList = [...yourList];
        const artwork = yourNextList.find(a => a.id === artworkId);
        if (artwork) {
            artwork.seen = nextSeen;
            setYourList(yourNextList);
        }
    };

    return (
        <>
            <h1>艺术愿望清单</h1>
            <h2>我想看的艺术清单:</h2>
            <ItemList artworks={myList} onToggle={handleToggleMyList} />
            <h2>你想看的艺术清单:</h2>
            <ItemList artworks={yourList} onToggle={handleToggleYourList} />
        </>
    );
};

// 定义 ItemList 组件的 props 类型
type ItemListProps = {
    artworks: Artwork[];
    onToggle: (artworkId: number, nextSeen: boolean) => void;
};

// 定义 ItemList 组件
const ItemList: React.FC<ItemListProps> = ({ artworks, onToggle }) => {
    return (
        <ul>
            {artworks.map((artwork) => (
                <li key={artwork.id}>
                    <label>
                        <input
                            type="checkbox"
                            checked={artwork.seen}
                            onChange={(e) => {
                                onToggle(artwork.id, e.target.checked);
                            }}
                        />
                        {artwork.title}
                    </label>
                </li>
            ))}
        </ul>
    );
};

export default App;

在这里插入图片描述

问题出在下面这段代码中:

 const myNextList = [...myList];
 const artwork = myNextList.find(a => a.id === artworkId);
 if (artwork) {
     artwork.seen = nextSeen;
     setMyList(myNextList);
 }

虽然 myNextList 这个数组是新的,但是其内部的元素本身与原数组 myList 是相同的。因此,修改 artwork.seen,其实是在修改原始的 artwork 对象。而这个 artwork 对象也被 yourList 使用,这样就带来了 bug。这样的 bug 可能难以想到,但好在如果你避免直接修改 state,它们就会消失。

你可以使用 map 在没有 mutation 的前提下将一个旧的元素替换成更新的版本。

setMyList(myList.map(artwork => {
  if (artwork.id === artworkId) {
    // 创建包含变更的*新*对象
    return { ...artwork, seen: nextSeen };
  } else {
    // 没有变更
    return artwork;
  }
}));

此处的 … 是一个对象展开语法,被用来创建一个对象的拷贝.

通过这种方式,没有任何现有的 state 中的元素会被改变,bug 也就被修复了。

import React, { useState } from'react';

// 定义 Artwork 类型,描述艺术作品的结构
type Artwork = {
    id: number;
    title: string;
    seen: boolean;
};

// 定义初始艺术作品列表
const initialList: Artwork[] = [
    { id: 0, title: 'Big Bellies', seen: false },
    { id: 1, title: 'Lunar Landscape', seen: false },
    { id: 2, title: 'Terracotta Army', seen: true },
];

// 定义 BucketList 组件的类型
type BucketListProps = {};

// BucketList 组件
const App: React.FC = (props: BucketListProps) => {
    const [myList, setMyList] = useState<Artwork[]>(initialList);
    const [yourList, setYourList] = useState<Artwork[]>(initialList);

    // 处理 myList 中艺术作品状态切换的函数
    const handleToggleMyList=(artworkId: number, nextSeen: boolean)=> {
        setMyList(myList.map((artwork: Artwork) => {
            if (artwork.id === artworkId) {
                // 创建包含变更的*新*对象
                return { ...artwork, seen: nextSeen };
            } else {
                // 没有变更
                return artwork;
            }
        }));
    }

    // 处理 yourList 中艺术作品状态切换的函数
    const handleToggleYourList=(artworkId: number, nextSeen: boolean)=> {
        setYourList(yourList.map((artwork: Artwork) => {
            if (artwork.id === artworkId) {
                // 创建包含变更的*新*对象
                return { ...artwork, seen: nextSeen };
            } else {
                // 没有变更
                return artwork;
            }
        }));
    }

    return (
        <>
            <h1>艺术愿望清单</h1>
            <h2>我想看的艺术清单:</h2>
            <ItemList
                artworks={myList}
                onToggle={handleToggleMyList} />
            <h2>你想看的艺术清单:</h2>
            <ItemList
                artworks={yourList}
                onToggle={handleToggleYourList} />
        </>
    );
}
export default App

// 定义 ItemList 组件的 props 类型
type ItemListProps = {
    artworks: Artwork[];
    onToggle: (artworkId: number, nextSeen: boolean) => void;
};

// ItemList 组件
const ItemList=(props: ItemListProps)=>{
    return (
        <ul>
            {props.artworks.map((artwork: Artwork) => (
                <li key={artwork.id}>
                    <label>
                        <input
                            type="checkbox"
                            checked={artwork.seen}
                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                                props.onToggle(
                                    artwork.id,
                                    e.target.checked
                                );
                            }}
                        />
                        {artwork.title}
                    </label>
                </li>
            ))}
        </ul>
    );
}

在这里插入图片描述

通常来讲,你应该只直接修改你刚刚创建的对象。如果你正在插入一个新的 artwork,你可以修改它,但是如果你想要改变的是 state 中已经存在的东西,你就需要先拷贝一份了。

使用 Immer 编写简洁的更新逻辑

在没有 mutation 的前提下更新嵌套数组可能会变得有点重复。就像对对象一样:

通常情况下,你应该不需要更新处于非常深层级的 state 。如果你有此类需求,你或许需要调整一下数据的结构,让数据变得扁平一些。
如果你不想改变 state 的数据结构,你也许会更喜欢使用 Immer ,它让你可以继续使用方便的,但会直接修改原值的语法,并负责为你生成拷贝值。
下面是我们用 Immer 来重写的艺术愿望清单的例子:

import React from "react";
import { useImmer } from 'use-immer';
// 定义 Artwork 类型
type Artwork = {
    id: number;
    title: string;
    seen: boolean;
};

// 定义初始列表
const initialList: Artwork[] = [
    { id: 0, title: 'Big Bellies', seen: false },
    { id: 1, title: 'Lunar Landscape', seen: false },
    { id: 2, title: 'Terracotta Army', seen: true },
];

// 定义 BucketList 组件
const BucketList:React.FC=()=> {
    const [myList, updateMyList] = useImmer<Artwork[]>(initialList);
    const [yourList, updateYourList] = useImmer<Artwork[]>(initialList);

    // 处理我的列表中项目的切换
    const handleToggleMyList=(id: number, nextSeen: boolean)=> {
        updateMyList((draft) => {
            const artwork = draft.find((a) => a.id === id);
            if (artwork) {
                artwork.seen = nextSeen;
            }
        });
    }

    // 处理你的列表中项目的切换
    const handleToggleYourList=(artworkId: number, nextSeen: boolean)=> {
        updateYourList((draft) => {
            const artwork = draft.find((a) => a.id === artworkId);
            if (artwork) {
                artwork.seen = nextSeen;
            }
        });
    }

    return (
        <>
            <h1>艺术愿望清单</h1>
            <h2>我想看的艺术清单:</h2>
            <ItemList artworks={myList} onToggle={handleToggleMyList} />
            <h2>你想看的艺术清单:</h2>
            <ItemList artworks={yourList} onToggle={handleToggleYourList} />
        </>
    );
}

export default BucketList

// 定义 ItemList 组件的 props 类型
type ItemListProps = {
    artworks: Artwork[];
    onToggle: (id: number, nextSeen: boolean) => void;
};

// 定义 ItemList 组件
const ItemList=({ artworks, onToggle }: ItemListProps) =>{
    return (
        <ul>
            {artworks.map((artwork: Artwork) => (
                <li key={artwork.id}>
                    <label>
                        <input
                            type="checkbox"
                            checked={artwork.seen}
                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                                onToggle(artwork.id, e.target.checked);
                            }}
                        />
                        {artwork.title}
                    </label>
                </li>
            ))}
        </ul>
    );
}

在这里插入图片描述
请注意当使用 Immer 时,类似 artwork.seen = nextSeen 这种会产生 mutation 的语法不会再有任何问题了:

updateMyTodos(draft => {
  const artwork = draft.find(a => a.id === artworkId);
  artwork.seen = nextSeen;
});

这是因为你并不是在直接修改原始的 state,而是在修改 Immer 提供的一个特殊的 draft 对象。同理,你也可以为 draft 的内容使用 push() 和 pop() 这些会直接修改原值的方法。

在幕后,Immer 总是会根据你对 draft 的修改来从头开始构建下一个 state。这使得你的事件处理程序非常的简洁,同时也不会直接修改 state。

摘要

  • 你可以把数组放入 state 中,但你不应该直接修改它。
  • 不要直接修改数组,而是创建它的一份 新的 拷贝,然后使用新的数组来更新它的状态。
  • 你可以使用 […arr, newItem] 这样的数组展开语法来向数组中添加元素。
  • 你可以使用 filter() 和 map() 来创建一个经过过滤或者变换的数组。
  • 你可以使用 Immer 来保持代码简洁。

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

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

相关文章

ubantu18.04HDFS编程实践(Hadoop3.1.3)

说明&#xff1a;本文图片较多&#xff0c;耐心等待加载。&#xff08;建议用电脑&#xff09; 注意所有打开的文件都要记得保存。 第一步&#xff1a;准备工作 本文是在之前Hadoop搭建完集群环境后继续进行的&#xff0c;因此需要读者完成我之前教程的所有操作。 第二步&am…

MySQL快速入门篇---库的操作

目录 一、创建数据库 1.语法 2.示例 二、查看数据库 1.语法 三、字符集编码和校验&#xff08;排序&#xff09;规则 1.查看数据库支持的字符集编码 2.查看数据库支持的排序规则 3.查看系统默认字符集和排序规则 3.1.查看系统默认字符集 3.2.查看系统默认排序规则 ​…

【已更新完毕】2025华中杯B题数学建模网络挑战赛思路代码文章教学:校园共享单车的调度与维护问题

完整内容请看文末最后的推广群 构建校园共享单车的调度与维护问题 摘要 共享单车作为一种便捷、环保的短途出行工具&#xff0c;近年来在高校校园内得到了广泛应用。然而&#xff0c;共享单车的运营也面临一些挑战。某高校引入共享单车后&#xff0c;委托学生对运营情况进行调…

NO.92十六届蓝桥杯备战|图论基础-最小生成树-Prim算法-Kruskal算法|买礼物|繁忙的都市|滑雪(C++)

一个具有n个顶点的连通图&#xff0c;其⽣成树为包含n-1条边和所有顶点的极⼩连通⼦图。对于⽣成树来说&#xff0c;若砍去⼀条边就会使图不连通图&#xff1b;若增加⼀条边就会形成回路。 ⼀个图的⽣成树可能有多个&#xff0c;将所有⽣成树中权值之和最⼩的树称为最⼩⽣成树…

第十四节:实战场景-何实现全局状态管理?

React.createElement调用示例 Babel插件对JSX的转换逻辑 React 全局状态管理实战与 JSX 转换原理深度解析 一、React 全局状态管理实现方案 1. Context API useReducer 方案&#xff08;轻量级首选&#xff09; // 创建全局 Context 对象 const GlobalContext createConte…

数据驱动、精准协同:高端装备制造业三位一体生产管控体系构建

开篇引入 鉴于集团全面推行生产运营体建设以及对二级单位生产过程管控力度逐步加强&#xff0c;某高端装备制造企业生产部长王总正在开展新的一年企业生产管控规划工作&#xff0c;为了能够更好地进行体系规划与建设应用&#xff0c;特邀请智能制造专家小智来进行讨论交流。 王…

航电系统之通信技术篇

航电系统&#xff08;航空电子系统&#xff09;的通信技术是现代航空器的核心技术之一&#xff0c;其核心目标是实现飞行器内部各系统之间以及飞行器与外部设备&#xff08;如地面控制中心、其他飞行器等&#xff09;之间高效、可靠的信息交互。随着航空技术的不断发展&#xf…

发现“横”字手写有难度,对比两个“横”字

我发现手写体“横”字“好看”程度&#xff0c;难以比得上印刷体&#xff1a; 两个从方正简体启体来的“横”字&#xff1a; 哪个更好看&#xff1f;我是倾向于左边一点。 <div style"transform: rotate(180deg); display: inline-block;"> 左边是我从方正简…

深度学习3.1 线性回归

3.1.1 线性回归的基本概念 损失函数 梯度下降 3.1.2 向量化加速 %matplotlib inline import math import time import numpy as np import torch from d2l import torch as d2ln 1000000 #本机为了差距明显&#xff0c;选择数据较大&#xff0c;运行时间较长&#xff0c;可选…

番外篇 | SEAM-YOLO:引入SEAM系列注意力机制,提升遮挡小目标的检测性能

前言:Hello大家好,我是小哥谈。SEAM(Squeeze-and-Excitation Attention Module)系列注意力机制是一种高效的特征增强方法,特别适合处理遮挡和小目标检测问题。该机制通过建模通道间关系来自适应地重新校准通道特征响应。在遮挡小目标检测中的应用优势包括:1)通道注意力增强…

SpringBoot ApplicationEvent:事件发布与监听机制

文章目录 引言一、事件机制的基本概念二、创建自定义事件2.1 定义事件类2.2 发布事件2.3 简化的事件发布 三、创建事件监听器3.1 使用EventListener注解3.2 实现ApplicationListener接口3.3 监听非ApplicationEvent类型的事件 四、事件监听的高级特性4.1 条件事件监听4.2 异步事…

广东2024信息安全管理与评估一阶段答案截图

2023-2024 学年广东省职业院校技能大赛 高等职业教育组 信息安全管理与评估 赛题一 模块一 网络平台搭建与设备安全防护 一、 比赛时间 本阶段比赛时间为 180 分钟。 二、 赛项信息 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一…

安卓手机如何改ip地址教程

对于安卓手机用户而言&#xff0c;ip修改用在电商、跨境电商、游戏搬砖、社交软件这些需要开多个账号的项目。因为多个设备或账号又不能在同一ip网络下&#xff0c;所以修改手机的IP地址防检测成为一个必要的操作。以下是在安卓手机上更改IP地址的多种方法及详细步骤&#xff0…

(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)

目录 演示视频&#xff1a; 源代码 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代码解析与教程&#xff1a; Dealy模块 LCD1602模块 Key模块 I2C总线模块 AT24C02模块 /E2PROM模块 main模块 演示视频&#xff1a; &…

STL简介 + string【上】

一 . STL简介 1.1 什么是STL STL&#xff08;standard template libaray - 标准模板库) : 是C标准库的重要组成部分 &#xff0c; 不仅是一个可复用的组件库 &#xff0c; 而且是一个包罗 数据结构 与 算法 的软件框架 。 注意 &#xff1a; 是标准库的一部分 &#xff…

【Bluedroid】A2DP Sink播放流程源码分析(二)

接上一篇继续分析:【Bluedroid】A2DP Sink播放流程源码分析(一)_安卓a2dp sink播放流程-CSDN博客 AVDTP接收端(Sink)流事件处理 bta_av_sink_data_cback 是 Bluedroid 中 A2DP Sink 角色的 AVDTP 数据回调函数,负责处理接收端的音频数据事件,将底层接收到的音频数据传递…

redis利用备忘录

fofa: icon_hash"864611937" 防护&#xff1a; redis的安全设置&#xff1a;设置完毕&#xff0c;需要重加载配置文件启动redis 1.绑定内网ip地址进行访问 2. requirepass设置redis密码 3.保护模式开启protected-mode开启&#xff08;默认开启&#xff09; 4.最好把…

SAP系统中MD01与MD02区别

知识点普及&#xff0d;MD01与MD02区别 1、从日常业务中&#xff0c;我们都容易知道MD01是运行全部物料&#xff0c;MD02是运行单个物料 2、在做配置测试中&#xff0c;也出现过MD02可以跑出物料&#xff0c;但是MD01跑不出的情况。 3、MD01与MD02的差异: 3.1、只要在物料主数…

ubuntu学习day3

3 编译与调试 3.1 gcc/g编译器 当我们进行编译的时候&#xff0c;要使用一系列的工具&#xff0c;我们称之为工具链。SDK就是编译工具链的简写&#xff0c;我们所使用的是gcc系列编译工具链。使用-v参数来查看gcc的版本&#xff0c;从而确定某些语法特性是否可用&#xff0c;…

6.8.最小生成树

一.复习&#xff1a; 1.生成树&#xff1a; 对于一个连通的无向图&#xff0c;假设图中有n个顶点&#xff0c;如果能找到一个符合以下要求的子图&#xff1a; 子图中包含图中所有的顶点&#xff0c;同时各个顶点保持连通&#xff0c; 而且子图的边的数量只有n-1条&#xff0…