【rCore OS 开源操作系统】Rust 智能指针

news2024/10/19 16:39:38

前置知识点

何为“智能”

在 Rust 中,“智能指针”是指那些实现了特定智能行为的指针类型。这些智能行为通常包括内存管理生命周期跟踪以及所有权转移等

常见智能指针

Box

Box<T> 是 Rust 中最简单的智能指针类型之一,它用于堆分配的内存。Box<T> 允许你在堆上分配类型 T 的对象,并且它实现了 Deref trait,使得你可以像操作栈上的对象一样操作堆上的对象。

说人话:就是用这个,可以把本来该放到栈上的内容,放到堆上

let boxed_num = Box::new(5); // 堆上放一个 5,然后 boxed_num 就是引用
println!("Boxed number is: {}", *boxed_num); // 所以这里要解引用
Rc 和 Arc

前者后者的区别就是,前者用于一般场景,后者是 Aotomic 所以用于多线程常见

Rc<T>(Reference Counted)用于共享所有权的情况,即多个地方需要访问同一个数据。它通过引用计数来跟踪有多少个 Rc 指向同一个数据。

Arc<T>Atomic Rc)与 Rc<T> 类似,但它是线程安全的,适用于多线程环境中共享数据。

说人话就是,一个堆上的数据,要被多处共享,但是 rust 默认情况下有个所有权机制,直接共享就有问题要报错,要用这个包一下才能共享

let rc_str = Rc::new(String::from("hello"));
let clone = Rc::clone(&rc_str);

println!("Original string: {}", rc_str);
println!("Cloned string: {}", clone);

Arc<T> 也是同理,此处不再赘述。后面在练习题中看具体使用。

RefCell

RefCell<T> 提供了对数据的可变借用,这对于在单线程中打破 Rust 的借用规则很有用。RefCell<T> 使用运行时检查来保证互斥性。
RefCell<T> 通常用于需要在运行时决定借用关系的情况,例如在递归数据结构中。

如果你是做 Java 的,一定很熟悉多线程加法!对,也就是那么个道理。
具体的代码放到题目中体现,看看 Rust 如何用 RefCell<T>实现

Cow

Cow<T>Clone and Write 的缩写。

作者真是个取名天才, 这谁能想得到啊…

Cow 是一个智能指针类型,它允许你在不进行克隆的情况下处理字符串或其他数据类型。具体来说,Cow 可以在以下两种情况下工作:

  • 借用(Borrow):当数据不需要被修改时,Cow 只是一个借用。
  • 克隆(Clone):当数据需要被修改时,Cow 会克隆数据并提供一个可变版本。

我称之为,“懒克隆”
代码看后面的题目。

let original_str = "Hello, world!";

// 借用字符串
let borrowed_str = Cow::from(original_str);
println!("Borrowed str: {:?}", borrowed_str);

// 修改字符串
let modified_str = Cow::from("Hello, Rustaceans!");
println!("Modified str: {:?}", modified_str);

// 如果需要修改,`Cow` 会克隆字符串
let mut mutable_str = Cow::from("Hello, Rust!");
mutable_str.to_mut().push_str("aceans");
println!("Mutable str after modification: {:?}", mutable_str);

Weak

Weak<T>Rc<T>Arc<T> 结合使用,当不再需要强引用时,可以使用 Weak<T> 来保持对对象的弱引用,这样即使有弱引用存在,对象也可以被垃圾回收。
这对于实现某些设计模式(如观察者模式)很有用。

感觉也不怎么用得到这个…学前端学了这么久唯一的感受就是在 Vue 的实现里有用过,其他还真是一概不知…

NonNull

NonNull<T> 是一个非空指针,它并不包含任何智能行为,但是它可以用来表示未经过 Rust 内存管理系统管理的裸指针。
这对于与 C/C++ 代码交互或操作底层内存时很有用。

(挠头)…感觉也没什么用

练习题

Arc

题目

来吧,实现一些多线程加法。

// arc1.rs
//
// In this exercise, we are given a Vec of u32 called "numbers" with values
// ranging from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ] We would like to use this
// set of numbers within 8 different threads simultaneously. Each thread is
// going to get the sum of every eighth value, with an offset.
//
// The first thread (offset 0), will sum 0, 8, 16, ...
// The second thread (offset 1), will sum 1, 9, 17, ...
// The third thread (offset 2), will sum 2, 10, 18, ...
// ...
// The eighth thread (offset 7), will sum 7, 15, 23, ...
//
// Because we are using threads, our values need to be thread-safe.  Therefore,
// we are using Arc.  We need to make a change in each of the two TODOs.
//
// Make this code compile by filling in a value for `shared_numbers` where the
// first TODO comment is, and create an initial binding for `child_numbers`
// where the second TODO comment is. Try not to create any copies of the
// `numbers` Vec!
//
// Execute `rustlings hint arc1` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

#![forbid(unused_imports)] // Do not change this, (or the next) line.
use std::sync::Arc;
use std::thread;

fn main() {
    let numbers: Vec<_> = (0..100u32).collect();
    let shared_numbers = // TODO
    let mut joinhandles = Vec::new();

    for offset in 0..8 {
        let child_numbers = // TODO
        joinhandles.push(thread::spawn(move || {
            let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
            println!("Sum of offset {} is {}", offset, sum);
        }));
    }
    for handle in joinhandles.into_iter() {
        handle.join().unwrap();
    }
}

题解
#![forbid(unused_imports)] // Do not change this, (or the next) line.
use std::sync::Arc;
use std::thread;

fn main() {
    // collect 会把 迭代器 转为 Vec<_> 的 vec(是的,根据类型推导
    let numbers: Vec<_> = (0..100u32).collect();
    // arc 和 rc 都是支持计数的,但是 arc 是原子的、线程安全的,而 rc 不是。
    let shared_numbers = Arc::new(numbers);
    let mut joinhandles = Vec::new();

    for offset in 0..8 {
        // 这里为啥不直接用 shared_numbers 呢?
        // 是因为借用检查:Rust 的借用检查器(borrow checker)会阻止你直接将 shared_numbers 传入多个线程中的闭包,
        // 因为这会导致多个线程同时访问同一个引用——这在 Rust 中是不允许的
        let child_numbers = Arc::clone(&shared_numbers);
        //在 Rust 中,闭包默认捕获外部作用域中的变量的方式有两种: 借用(默认情况,只读这些变量) 和 移动(可以改这些变量)
        // Rust 不允许多个线程同时访问同一个引用
        // 这里由于是使用基本数据类型——天然支持 copy trait,所以可以直接通过移动获取一份副本
        joinhandles.push(thread::spawn(move || {
            // iter() 返回的是 &u32,filter 一般是都是 &xxx 引用,所以二者叠加就是 &&n
            let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
            println!("Sum of offset {} is {}", offset, sum);
        }));
    }
    for handle in joinhandles.into_iter() {
        handle.join().unwrap();
    }
}

Rc

题目

主要是引用计数的知识点。
RC:clone 去克隆一个引用。
场景说实话有点难,好几次没记住行星名字…反复对照了好几次…

// rc1.rs
//
// In this exercise, we want to express the concept of multiple owners via the
// Rc<T> type. This is a model of our solar system - there is a Sun type and
// multiple Planets. The Planets take ownership of the sun, indicating that they
// revolve around the sun.
//
// Make this code compile by using the proper Rc primitives to express that the
// sun has multiple owners.
//
// Execute `rustlings hint rc1` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

use std::rc::Rc;

#[derive(Debug)]
struct Sun {}

#[derive(Debug)]
enum Planet {
    Mercury(Rc<Sun>),
    Venus(Rc<Sun>),
    Earth(Rc<Sun>),
    Mars(Rc<Sun>),
    Jupiter(Rc<Sun>),
    Saturn(Rc<Sun>),
    Uranus(Rc<Sun>),
    Neptune(Rc<Sun>),
}

impl Planet {
    fn details(&self) {
        println!("Hi from {:?}!", self)
    }
}

fn main() {
    let sun = Rc::new(Sun {});
    println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference

    let mercury = Planet::Mercury(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
    mercury.details();

    let venus = Planet::Venus(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
    venus.details();

    let earth = Planet::Earth(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
    earth.details();

    let mars = Planet::Mars(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
    mars.details();

    let jupiter = Planet::Jupiter(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
    jupiter.details();

    // TODO
    let saturn = Planet::Saturn(Rc::new(Sun {}));
    println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
    saturn.details();

    // TODO
    let uranus = Planet::Uranus(Rc::new(Sun {}));
    println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
    uranus.details();

    // TODO
    let neptune = Planet::Neptune(Rc::new(Sun {}));
    println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
    neptune.details();

    assert_eq!(Rc::strong_count(&sun), 9);

    drop(neptune);
    println!("reference count = {}", Rc::strong_count(&sun)); // 8 references

    drop(uranus);
    println!("reference count = {}", Rc::strong_count(&sun)); // 7 references

    drop(saturn);
    println!("reference count = {}", Rc::strong_count(&sun)); // 6 references

    drop(jupiter);
    println!("reference count = {}", Rc::strong_count(&sun)); // 5 references

    drop(mars);
    println!("reference count = {}", Rc::strong_count(&sun)); // 4 references

    // TODO
    println!("reference count = {}", Rc::strong_count(&sun)); // 3 references

    // TODO
    println!("reference count = {}", Rc::strong_count(&sun)); // 2 references

    // TODO
    println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference

    assert_eq!(Rc::strong_count(&sun), 1);
}

题解

修改也就是复用Sun引用就好,而不是新建一个引用。
这里还涉及到一个全局函数 drop, 用来手动析构,同时可以让Rc的引用减一。


fn main() {
    let sun = Rc::new(Sun {});
    println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference	
	// 省略 部分 代码!!!!
	// 省略 部分 代码!!!!
	// 省略 部分 代码!!!!


    // TODO
    let saturn = Planet::Saturn(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
    saturn.details();

    // TODO
    let uranus = Planet::Uranus(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
    uranus.details();

    // TODO
    let neptune = Planet::Neptune(Rc::clone(&sun));
    println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
    neptune.details();

    assert_eq!(Rc::strong_count(&sun), 9);

    drop(neptune);
    println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
	// 省略 部分 代码!!!!
	// 省略 部分 代码!!!!
	// 省略 部分 代码!!!!
 
    drop(mars);
    println!("reference count = {}", Rc::strong_count(&sun)); // 4 references

    // TODO
    drop(mercury);
    println!("reference count = {}", Rc::strong_count(&sun)); // 3 references

    // TODO
    drop(venus);
    println!("reference count = {}", Rc::strong_count(&sun)); // 2 references

    // TODO
    drop(earth);
    println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference

    assert_eq!(Rc::strong_count(&sun), 1);
}

Box

题目

这个题目好就好在,让我知道了什么场景下会用到 Box<T>

是啊,什么场景下不能放栈上而要放到堆上?
什么,你说数据结构超级大的时候?
那这会不会是设计不合理呢,什么栈上数据结构能 辣么大?

// box1.rs
//
// At compile time, Rust needs to know how much space a type takes up. This
// becomes problematic for recursive types, where a value can have as part of
// itself another value of the same type. To get around the issue, we can use a
// `Box` - a smart pointer used to store data on the heap, which also allows us
// to wrap a recursive type.
//
// The recursive type we're implementing in this exercise is the `cons list` - a
// data structure frequently found in functional programming languages. Each
// item in a cons list contains two elements: the value of the current item and
// the next item. The last item is a value called `Nil`.
//
// Step 1: use a `Box` in the enum definition to make the code compile
// Step 2: create both empty and non-empty cons lists by replacing `todo!()`
//
// Note: the tests should not be changed
//
// Execute `rustlings hint box1` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

#[derive(PartialEq, Debug)]
pub enum List {
    Cons(i32, List),
    Nil,
}

fn main() {
    println!("This is an empty cons list: {:?}", create_empty_list());
    println!(
        "This is a non-empty cons list: {:?}",
        create_non_empty_list()
    );
}

pub fn create_empty_list() -> List {
    todo!()
}

pub fn create_non_empty_list() -> List {
    todo!()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_create_empty_list() {
        assert_eq!(List::Nil, create_empty_list())
    }

    #[test]
    fn test_create_non_empty_list() {
        assert_ne!(create_empty_list(), create_non_empty_list())
    }
}

题解

我的了个 Holy Gosh 啊…竟然是递归数据结构…确实没想到…
不过这样说来,rust 竟然是把 enum 这类东西放栈上,有点离谱…

// Box 是一种智能指针,让我们直接在堆上分配内存,绕过栈内存的大小限制(放到堆上
// 比如下面这个 List,可以看到它的 Cons 成员中还有 List,这就产生了递归,Rust 会认为在栈上无法存下,所以需要使用 Box 改到堆上
#[derive(PartialEq, Debug)]
pub enum List {
    Cons(i32, Box<List>),
    Nil,
}

fn main() {
    println!("This is an empty cons list: {:?}", create_empty_list());
    println!(
        "This is a non-empty cons list: {:?}",
        create_non_empty_list()
    );
}

pub fn create_empty_list() -> List {
    List::Nil
}

pub fn create_non_empty_list() -> List {
    List::Cons(123123, Box::new(List::Nil))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_create_empty_list() {
        assert_eq!(List::Nil, create_empty_list())
    }

    #[test]
    fn test_create_non_empty_list() {
        assert_ne!(create_empty_list(), create_non_empty_list())
    }
}

Cow

题目
// cow1.rs
//
// This exercise explores the Cow, or Clone-On-Write type. Cow is a
// clone-on-write smart pointer. It can enclose and provide immutable access to
// borrowed data, and clone the data lazily when mutation or ownership is
// required. The type is designed to work with general borrowed data via the
// Borrow trait.
//
// This exercise is meant to show you what to expect when passing data to Cow.
// Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the
// TODO markers.
//
// Execute `rustlings hint cow1` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

use std::borrow::Cow;

fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {
    for i in 0..input.len() {
        let v = input[i];
        if v < 0 {
            // Clones into a vector if not already owned.
            input.to_mut()[i] = -v;
        }
    }
    input
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reference_mutation() -> Result<(), &'static str> {
        // Clone occurs because `input` needs to be mutated.
        let slice = [-1, 0, 1];
        let mut input = Cow::from(&slice[..]);
        match abs_all(&mut input) {
            Cow::Owned(_) => Ok(()),
            _ => Err("Expected owned value"),
        }
    }

    #[test]
    fn reference_no_mutation() -> Result<(), &'static str> {
        // No clone occurs because `input` doesn't need to be mutated.
        let slice = [0, 1, 2];
        let mut input = Cow::from(&slice[..]);
        match abs_all(&mut input) {
            // TODO
        }
    }

    #[test]
    fn owned_no_mutation() -> Result<(), &'static str> {
        // We can also pass `slice` without `&` so Cow owns it directly. In this
        // case no mutation occurs and thus also no clone, but the result is
        // still owned because it was never borrowed or mutated.
        let slice = vec![0, 1, 2];
        let mut input = Cow::from(slice);
        match abs_all(&mut input) {
            // TODO
        }
    }

    #[test]
    fn owned_mutation() -> Result<(), &'static str> {
        // Of course this is also the case if a mutation does occur. In this
        // case the call to `to_mut()` returns a reference to the same data as
        // before.
        let slice = vec![-1, 0, 1];
        let mut input = Cow::from(slice);
        match abs_all(&mut input) {
            // TODO
        }
    }
}

题解
// cow1.rs
//
// This exercise explores the Cow, or Clone-On-Write type. Cow is a
// clone-on-write smart pointer. It can enclose and provide immutable access to
// borrowed data, and clone the data lazily when mutation or ownership is
// required. The type is designed to work with general borrowed data via the
// Borrow trait.
//
// This exercise is meant to show you what to expect when passing data to Cow.
// Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the
// TODO markers.
//
// Execute `rustlings hint cow1` or use the `hint` watch subcommand for a hint.

use std::borrow::Cow;

fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {
    for i in 0..input.len() {
        let v = input[i];
        if v < 0 {
            // Clones into a vector if not already owned.
            input.to_mut()[i] = -v;
        }
    }
    input
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reference_mutation() -> Result<(), &'static str> {
        // Clone occurs because `input` needs to be mutated.
        let slice = [-1, 0, 1];
        let mut input = Cow::from(&slice[..]);
        // 这里用了 Cow::Owned 相当于会拷贝一份
        match abs_all(&mut input) {
            Cow::Owned(_) => Ok(()),
            _ => Err("Expected owned value"),
        }
    }

    #[test]
    fn reference_no_mutation() -> Result<(), &'static str> {
        // No clone occurs because `input` doesn't need to be mutated.
        let slice = [0, 1, 2];
        let mut input = Cow::from(&slice[..]);
        match abs_all(&mut input) {
            Cow::Borrowed(_) => Ok(()),
            _ => Err("Expected owned value"),
        }
    }

    #[test]
    fn owned_no_mutation() -> Result<(), &'static str> {
        // We can also pass `slice` without `&` so Cow owns it directly. In this
        // case no mutation occurs and thus also no clone, but the result is
        // still owned because it was never borrowed or mutated.
        let slice = vec![0, 1, 2];
        let mut input = Cow::from(slice);
        match abs_all(&mut input) {
            Cow::Owned(_) => Ok(()),
            _ => Err("Expected owned value"),
        }
    }

    #[test]
    fn owned_mutation() -> Result<(), &'static str> {
        // Of course this is also the case if a mutation does occur. In this
        // case the call to `to_mut()` returns a reference to the same data as
        // before.
        let slice = vec![-1, 0, 1];
        let mut input = Cow::from(slice);
        match abs_all(&mut input) {
            Cow::Owned(_) => Ok(()),
            _ => Err("Expected owned value"),
        }
    }
}

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

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

相关文章

实现双向链表的增删改查

头文件 #pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <stdbool.h> typedef int LTDataType; typedef struct ListNode {LTDataType data;struct ListNode* prev;struct ListNode* next; } LTNode; //v…

QGraphics类型学习使用【Qt】【C++】

QGraphics类型学习使用 需求过程全部完整代码 首先已知&#xff0c;QGraphicsView&#xff0c;QGraphicsScene, QGraphicsItem&#xff0c;分别称为&#xff1a;视图&#xff0c;场景&#xff0c;图元&#xff0c;图表就是各种各样的元素&#xff0c;图片元素&#xff0c;线条元…

react18中在列表项中如何使用useRef来获取每项的dom对象

在react中获取dom节点都知道用ref&#xff0c;但是在一个列表循环中&#xff0c;这样做是行不通的&#xff0c;需要做进一步的数据处理。 实现效果 需求&#xff1a;点击每张图片&#xff0c;当前图片出现在可视区域。 代码实现 .box{border: 1px solid #000;list-style: …

ParallelsDesktop20最新版本虚拟机 一键切换系统 游戏娱乐两不误

让工作生活更高效&#xff1a;Parallels Desktop 20最新版本虚拟机的神奇之处 大家好&#xff01;&#x1f44b; 今天我要跟大家安利一款让我工作效率飞升的神器——Parallels Desktop 20最新版本虚拟机。作为一个日常需要在不同操作系统间来回穿梭的人&#xff0c;这款软件简直…

react18中的计算属性及useMemo的性能优化技巧

react18里面的计算属性和使用useMemo来提升组件性能的方法 计算属性 实现效果 代码实现 函数式组件极简洁的实现&#xff0c;就这样 import { useState } from "react"; function FullName() {const [firstName, setFirstName] useState("");const [la…

OpenCV高级图形用户界面(14)交互式地选择一个或多个感兴趣区域函数selectROIs()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 允许用户在给定的图像上选择多个 ROI。 该函数创建一个窗口&#xff0c;并允许用户使用鼠标来选择多个 ROI。控制方式&#xff1a;使用空格键或…

明日周刊-第23期

十月已过半&#xff0c;气温也转凉了&#xff0c;大家注意保温哦。冬吃萝卜&#xff0c;夏吃姜&#xff0c;在快要到来的冬季大家可以选择多吃点萝卜。 配图是本周末去商场抓娃娃的时候拍的照片&#xff0c;现在抓娃娃单次普遍都控制在1块钱以下了&#xff0c;还记得多年前的抓…

智能手表PPG技术原理:【图文讲解】

光体积变化描记图法&#xff08;Photoplethysmography&#xff0c;简称PPG&#xff09;是借光电手段在活体组织中监测血液容积变化的一种无创监测方法 目前智能手表比较标配的功能&#xff1a;血糖、血压、心电、心率、血氧 1&#xff1a;人体血管 先温习一下&#xff0c;人…

Java项目-基于Springboot的智慧养老平台项目(源码+文档).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、SpringClud、Vue、Mybaits Plus、ELementUI工具&…

TikTok广告账号被封?常见原因及解决方法分享

TikTok广告投放往往会给我们的账号带来高效曝光和精准流量&#xff0c;但同时许多用户也面临着一个困扰——广告账号被封禁的问题。将在此文一起商讨TikTok广告账号被封禁的原因&#xff0c;分析平台的具体规定&#xff0c;提供解决问题的应对策略&#xff0c;帮助大家有效规避…

PRCV 2024 - Day 1

2024年10月18日至10月20日&#xff0c;第七届中国模式识别与计算机视觉大会&#xff08;The 7th Chinese Conference on Pattern Recognition and Computer Vision, PRCV 2024&#xff09;在新疆乌鲁木齐的新疆国际会展中心举办&#xff0c;是国内顶级的模式识别和计算机视觉领…

专家系统简介

本文对基于规则的专家系统进行简介&#xff0c;举例专家系统的结构类似 MYCIN 系统&#xff0c;同时串联介绍专家系统的各种思想。需要注意的是&#xff0c;本文所述仅是专家系统的一种实现途径&#xff0c;其依赖规则进行知识表示和推理&#xff0c;另外还有基于语义网络、框架…

详解23种设计模式——第一部分:概述+创建型模式

目录 1. 概述 2. 创建型模式 2.1 简单&#xff08;静态&#xff09;工厂模式 2.1.1 介绍 2.1.2 实现 2.2 工厂模式 2.3 抽象工厂模式 2.4 单例模式 2.4.1 饿汉模式 2.4.2 懒汉模式 2.4.3 线程安全的懒汉式 2.4.4 DCL单例 - 高性能的懒汉式 2.5 建造者模式 2.6 原…

linux模拟:chrony同步时间

实验材料&#xff1a; 服务器&#xff1a;linux,红帽-9.1 客户端&#xff1a;linux&#xff0c;乌班图-18.4 Server/client; 安装chrony yum install -y chrony 查看chrony的状态&#xff1a; systemctl status chronyd 服务器&#xff1a; 在/etc/chrony.conf文件里面…

理解VSCODE基于配置的设置,避免臃肿

这节课我们讲两点&#xff1a; &#xff08;一&#xff09;下载、安装、汉化及美化 VSCODE&#xff1b; &#xff08;二&#xff09;理解VSCODE中基于配置&#xff08;Profiles&#xff09;的设置&#xff08;Settings&#xff09;&#xff0c;让 VSCODE 保持清爽。 &#xff0…

无极低码课程【redis windows下服务注册密码修改】

下载Windows版本的Redis linux环境 (自行下载) 1.打开官网https://redis.io/downloads/ windows环境 1.打开github https://github.com/microsoftarchive/redis/releases 然后选择你喜欢的版本zip或msi下载 2.这里下载zip版,解压后后,打开安装目录 3.双击redis-server…

学习莫烦python---神经网络

一、卷积神经网络区别 1、“卷积” 和 “神经网络”. 卷积也就是说神经网络不再是对每个像素的输入信息做处理了,而是图片上每一小块像素区域进行处理, 这种做法加强了图片信息的连续性. 使得神经网络能看到图形, 而非一个点. 这种做法同时也加深了神经网络对图片的理解 –翻译…

快充协议有哪些,都有哪些特点

什么是PD协议 PD协议是一种充电协议&#xff0c;全称为“USB Power Delivery&#xff08;USB PD&#xff09;”&#xff0c;是由USB-IF&#xff08;USB Implementers Forum&#xff09;组织制定的一种标准协议‌。它是一种基于USB接口的快速充电技术&#xff0c;可以实现高达1…

【无人机设计与控制】基于环形拓扑的多目标粒子群优化算法(MO_Ring_PSO_SCD)求解无人机

摘要 本文提出了一种基于环形拓扑的多目标粒子群优化算法 (MO-Ring-PSO-SCD) 用于解决无人机的三维路径规划问题。该算法同时优化了无人机路径的路径成本和威胁成本&#xff0c;通过粒子群算法的多目标优化能力实现路径选择。实验结果表明&#xff0c;与传统算法相比&#xff…

RFID在半导体天车的问题解决方案

RFID在半导体天车的问题解决方案 目前苏州某科技公司的半导体天车目前现阶段存在问题&#xff1a; &#xff08;1&#xff09;传统8寸晶圆加工过程中涉及几十道工序&#xff0c;目前都是采用人工搬运&#xff0c;容易产生污染物导致晶圆损坏&#xff0c;速度也比较慢&#xf…