当前位置: 首页 > news >正文

Maui学习笔记- SQLite简单使用案例02添加详情页

  • 我们继续上一个案例,实现一个可以修改当前用户信息功能。

    当用户点击某个信息时,跳转到信息详情页,然后可以点击编辑按钮导航到编辑页面。

创建项目 

  • 我们首先在ViewModels目录下创建UserDetailViewModel。

  • 实现从详情信息页面导航到编辑页面。

  • 这里要使用一个字典来传输对象。

public partial class UserDetailViewModel:ObservableObject,IQueryAttributable
{[ObservableProperty] private User itemUser;public Func<User, Task> ParentRefreshAction { get;set; }[RelayCommand]async Task ShowEditFormAsync(){var context = new UserContext();var editedItem = context.Users.FirstOrDefault(u => u.Id == ItemUser.Id);await Shell.Current.GoToAsync(nameof(UserEditPage),parameters: new Dictionary<string, object>{{ "ParentRefreshAction", (Func<User, Task>)ItemEditedAsync },{ "Item", editedItem }});}async Task ItemEditedAsync(User user) {ItemUser = user;await ParentRefreshAction(user);}public virtual void ApplyQueryAttributes(IDictionary<string, object> query){if (query.TryGetValue("Item",out object currentItem)){ItemUser = (User)currentItem;}if (query.TryGetValue("ParentRefreshAction",out object parentRefreshAction)){ParentRefreshAction = (Func<User, Task>)parentRefreshAction;}query.Clear();}
}
  • 创建用户详情页面,用来显示用户的全部信息。

  • 在ToolbarItem中添加一个命令导航到编辑页面。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:vm="clr-namespace:MauiApp3.ViewModels"Title="用户详情"x:Class="MauiApp3.Views.UserDetailPage"><ContentPage.BindingContext><vm:UserDetailViewModel/></ContentPage.BindingContext><ContentPage.ToolbarItems><ToolbarItem Text="编辑" Command="{Binding ShowEditFormCommand}"/></ContentPage.ToolbarItems><VerticalStackLayout><Label Text="{Binding ItemUser.Id}" FontSize="Large"/><Label Text="{Binding ItemUser.Name}" FontSize="Large"/><Label Text="{Binding ItemUser.Phone}" FontSize="Large"/><Label Text="{Binding ItemUser.Email}" FontSize="Large"/></VerticalStackLayout>
</ContentPage>
  • 更新UserEditViewModel,我们让他直接继承自UserDetailViewModel.

public partial class UserEditViewModel:UserDetailViewModel
{[ObservableProperty] private bool isNewItem;[RelayCommand]private async Task SaveAsync(){await using var context = new UserContext();if (IsNewItem){context.Users.Add(ItemUser);}else{context.Users.Attach(ItemUser);context.Entry(ItemUser).State = Microsoft.EntityFrameworkCore.EntityState.Modified;}context.SaveChangesAsync();await ParentRefreshAction(ItemUser);await Shell.Current.GoToAsync("..");}public override void ApplyQueryAttributes(IDictionary<string, object> query) {if (query.TryGetValue("IsNewItem", out object isNew)) {IsNewItem = (bool)isNew;}base.ApplyQueryAttributes(query);}
}

 

  • 修改MainViewModel。

public partial class MainViewModel:ObservableObject
{[ObservableProperty]ObservableCollection<User> users;[ObservableProperty] private bool refreshing;[RelayCommand]private async Task LoadUsersAsync(){await Task.Run(() =>{using var context = new UserContext();Users = new ObservableCollection<User>(context.Users);});Refreshing = false;}[RelayCommand]private void Showing(){Refreshing = true;}[RelayCommand]private void DeleteUser(User user){var context = new UserContext();context.Users.Remove(user);context.SaveChanges();Users.Remove(user);}[RelayCommand]private async Task ShowNewFormAsync(){await Shell.Current.GoToAsync(nameof(UserEditPage),parameters:new Dictionary<string, object>{{"ParentRefreshAction",(Func<User,Task>)RefreshAddedAsync},{"Item",new User()},{"IsNewItem",true}});}Task RefreshAddedAsync(User addedUser){Users.Add(addedUser);return Task.CompletedTask;}[RelayCommand]async Task ShowDetailFormAsync(User user){await Shell.Current.GoToAsync(nameof(UserDetailPage),parameters:new Dictionary<string, object>{{"ParentRefreshAction",(Func<User,Task>)RefreshEditedAsync},{"Item",user},});}async Task RefreshEditedAsync(User updataUser){int editedItemIndex = -1;await Task.Run(() =>{editedItemIndex = Users.Select((user, index) => new { user, index }).First(x => x.user.Id == updataUser.Id).index;});if (editedItemIndex==-1){return;}Users[editedItemIndex] = updataUser;}
}
  • 注册路由

public partial class AppShell : Shell
{public AppShell(){InitializeComponent();Routing.RegisterRoute(nameof(UserEditPage),typeof(UserEditPage));Routing.RegisterRoute(nameof(UserDetailPage),typeof(UserDetailPage));}
}

 

  • 在主页添加GestureRecognizers,对详情页面的跳转

<Grid RowDefinitions="40,40"ColumnDefinitions="*,*"Padding="10"><Grid.GestureRecognizers><TapGestureRecognizerCommand="{Binding Path=BindingContext.ShowDetailFormCommand,Source={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContentPage}}}"CommandParameter="{Binding}"/></Grid.GestureRecognizers>
 IOS下运行程序

 

我们实现了查看用户详情,并且可以修改

优化代码 

  • 我们要在数据库和视图模型之间提供一个抽象层,它能使项目有不同的模块区分,更明确的分离开。

  • 在项目中往往需要对多张表进行操作,我们创建一个泛型接口,来抽象对数据库中CURD。

  • 在Models中添加一个IRepository.cs文件

public interface IRepository<T> where T:class
{Task<T> GetByIdAsync(int id);Task<IEnumerable<T>> GetAllAsync();Task AddAsync(T item);Task UpdateAsync(T item);Task DeleteAsync(T item);}
  • 实现接口

public class UserRepository: IRepository<User>
{private readonly DbSet<User> DbSet;private readonly UserContext Context;public UserRepository(UserContext context){Context = context;DbSet = Context.Set<User>();}public async Task<User> GetByIdAsync(int id){return await Task.Run(() => DbSet.Find(id));}public async Task<IEnumerable<User>> GetAllAsync(){return await Task.Run(() => DbSet.ToList());}public async Task AddAsync(User item){DbSet.Add(item);await Task.CompletedTask;}public async Task UpdateAsync(User item){DbSet.Attach(item);Context.Entry(item).State = EntityState.Modified;await Task.CompletedTask;}public async Task DeleteAsync(User item){DbSet.Remove(item);await Task.CompletedTask;}
  • 创建工作单元,它的作用主要是作用于不同的数据表。

public class DbUnitOfWork:IDisposable,IUnitOfWork<User>
{readonly UserContext Context=new UserContext();private IRepository<User> userRepository;public IRepository<User> Items => userRepository ??= new UserRepository(Context);public void Dispose(){Context.Dispose();}public async Task SaveAsync(){await Task.Run(() => Context.SaveChangesAsync());}
}public interface IUnitOfWork<T> where T : class {IRepository<T> Items { get; } Task SaveAsync(); 
}
修改MainViewModel
  • LoadUserAsync

[RelayCommand]
private async Task LoadUsersAsync()
{using var uniOfWork = new DbUnitOfWork();Users = new ObservableCollection<User>(await uniOfWork.Items.GetAllAsync());Refreshing = false;
}
  • DeleteUserAsync

[RelayCommand]
private async Task DeleteUser(User user)
{using var uniOfWork = new DbUnitOfWork();await uniOfWork.Items.DeleteAsync(user);await uniOfWork.SaveAsync();Users.Remove(user);
}
修改CustomerEditViewModel
  • SaveAsync

[RelayCommand]
private async Task SaveAsync()
{using var unitOfWork = new DbUnitOfWork();if (IsNewItem)await unitOfWork.Items.AddAsync(ItemUser);elseawait unitOfWork.Items.UpdateAsync(ItemUser);await unitOfWork.SaveAsync();await ParentRefreshAction(ItemUser);await Shell.Current.GoToAsync("..");
}
修改UserDetailViewModel
  • ShowEditFormAsync

[RelayCommand]
async Task ShowEditFormAsync()
{using var unitOfWork = new DbUnitOfWork();var editedItem = await unitOfWork.Items.GetByIdAsync(ItemUser.Id);await Shell.Current.GoToAsync(nameof(UserEditPage),parameters: new Dictionary<string, object>{{ "ParentRefreshAction", (Func<User, Task>)ItemEditedAsync },{ "Item", editedItem }});
}

 数据库验证错误

  • 很多时候我们需要对用户输入的数据进行验证,有很多方法和形式,我们来看看在数据库层面如何做错误验证处理。并反馈在页面给用户。

  • 我们在UserContext中进行简单的数据约束

  • 使用try catch来捕获异常

protected override void OnModelCreating(ModelBuilder modelBuilder)
{//用户邮箱唯一modelBuilder.Entity<User>().HasIndex(u => u.Email).IsUnique();//用户名不能为空modelBuilder.Entity<User>().Property(u => u.Name).IsRequired();//初始化数据modelBuilder.Entity<User>().HasData(new User{Id = 1,Name = "张三",Email = "张三@163.com",Phone = "123456789"});base.OnModelCreating(modelBuilder);
}
修改MainViewModel
  • DeleteCustomerAsync

[RelayCommand]
private async Task DeleteUserAsync(User user)
{using var uniOfWork = new DbUnitOfWork();try{await uniOfWork.Items.DeleteAsync(user);await uniOfWork.SaveAsync();}catch (Exception ex){await Shell.Current.DisplayAlert("Error", ex.Message, "OK");return;}Users.Remove(user);
}
修改UserEditViewModel
  • SaveAsync

[RelayCommand]
private async Task SaveAsync()
{using var unitOfWork = new DbUnitOfWork();try{if (IsNewItem)await unitOfWork.Items.AddAsync(ItemUser);elseawait unitOfWork.Items.UpdateAsync(ItemUser);await unitOfWork.SaveAsync();}catch (Exception ex){await Shell.Current.DisplayAlert("Error", ex.Message, "OK");return;}await ParentRefreshAction(ItemUser);await Shell.Current.GoToAsync("..");
}
IOS下运行程序
  • 这里如果用户没有添加用户名,程序会提出错误信息。

在UI中验证数据 

  • 程序中,在将数据提交到数据库之前可以在UI层执行某些验证规则,可以在用户保存某些修改时告知用户,从而改善用户体验。

修改UserEditViewModel
  • 在编辑用户页面我们添加对用户名和邮箱的验证,并关联到保存命令上。

[NotifyCanExecuteChangedFor(nameof(SaveCommand))] [ObservableProperty]
private bool isEmailValid;[NotifyCanExecuteChangedFor(nameof(SaveCommand))] [ObservableProperty]
private bool isNameValid;bool CanSave() => IsEmailValid&& IsNameValid;[RelayCommand(CanExecute = nameof(CanSave))]
private async Task SaveAsync()
{using var unitOfWork = new DbUnitOfWork();try{if (IsNewItem)await unitOfWork.Items.AddAsync(ItemUser);elseawait unitOfWork.Items.UpdateAsync(ItemUser);await unitOfWork.SaveAsync();}catch (Exception ex){await Shell.Current.DisplayAlert("Error", ex.Message, "OK");return;}await ParentRefreshAction(ItemUser);await Shell.Current.GoToAsync("..");
}

 

  • 在UserEditPage文件中,我们添加一个样式来反馈给用户,并使用工具包中的ValidationBehavior来进行验证和绑定命令。

  • 这个验证很简单,当用户输入的内容不满足条件时,会使用我们设置的样式颜色来显示,保存按钮无法点击,当满足条件时颜色变为正常并可以保存内容。

  • <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:vm="clr-namespace:MauiApp3.ViewModels;assembly=MauiApp3"xmlns:toolkit = "http://schemas.microsoft.com/dotnet/2022/maui/toolkit"x:Class="MauiApp3.Views.UserEditPage"Title="新用户"><ContentPage.BindingContext><vm:UserEditViewModel/></ContentPage.BindingContext><ContentPage.Resources><Style TargetType="Entry" x:Key="invalidEntryStyle"><Setter Property="TextColor" Value="Red"></Setter></Style></ContentPage.Resources><Grid><VerticalStackLayout VerticalOptions="Start"><Entry Placeholder="用户名"Text="{Binding ItemUser.Name}"><Entry.Behaviors><toolkit:TextValidationBehavior InvalidStyle="{StaticResource invalidEntryStyle}"IsValid="{Binding IsNameValid}"Flags="ValidateOnValueChanged,ValidateOnAttaching"//内容长度不能小于5MinimumLength="5"/></Entry.Behaviors></Entry><Entry Placeholder="电话"Text="{Binding ItemUser.Phone}"/><Entry Placeholder="Email"Text="{Binding ItemUser.Email}"ReturnCommand="{Binding SaveCommand}"><Entry.Behaviors>//验证是否时正常的邮箱格式<toolkit:EmailValidationBehaviorInvalidStyle="{StaticResource invalidEntryStyle}"IsValid="{Binding IsEmailValid}"Flags="ValidateOnValueChanged,ValidateOnAttaching"/></Entry.Behaviors></Entry><Button Text="保存" Command="{Binding SaveCommand}"/></VerticalStackLayout><ActivityIndicator VerticalOptions="Center"HorizontalOptions="Center"IsRunning="{Binding SaveCommand.IsRunning}"/></Grid>
    </ContentPage>

IOS下运行程序 

相关文章:

Maui学习笔记- SQLite简单使用案例02添加详情页

我们继续上一个案例&#xff0c;实现一个可以修改当前用户信息功能。 当用户点击某个信息时&#xff0c;跳转到信息详情页&#xff0c;然后可以点击编辑按钮导航到编辑页面。 创建项目 我们首先在ViewModels目录下创建UserDetailViewModel。 实现从详情信息页面导航到编辑页面…...

VMware 中Ubuntu无网络连接/无网络标识解决方法【已解决】

参考文档 Ubuntu无网络连接/无网络标识解决方法_ubuntu没网-CSDN博客 再我们正常使用VMware时&#xff0c;就以Ubuntu举例可能有时候出现无网络连接&#xff0c;甚至出现无网络标识的情况&#xff0c;那么废话不多说直接上教程 环境&#xff1a;无网络 解决方案&#…...

完美世界前端面试题及参考答案

如何设置事件捕获和事件冒泡? 在 JavaScript 中,可以通过addEventListener方法来设置事件捕获和事件冒泡。该方法接收三个参数,第一个参数是事件类型,如click、mousedown等;第二个参数是事件处理函数;第三个参数是一个布尔值,用于指定是否使用事件捕获机制。当这个布尔值…...

新时代架构SpringBoot+Vue的理解(含axios/ajax)

文章目录 引言SpringBootThymeleafVueSpringBootSpringBootVue&#xff08;前端&#xff09;axios/ajaxVue作用响应式动态绑定单页面应用SPA前端路由 前端路由URL和后端API URL的区别前端路由的数据从哪里来的 Vue和只用三件套axios区别 引言 我是一个喜欢知其然又知其所以然的…...

代理模式 -- 学习笔记

代理模式学习笔记 什么是代理&#xff1f; 代理是一种设计模式&#xff0c;用户可以通过代理操作&#xff0c;而真正去进行处理的是我们的目标对象&#xff0c;代理可以在方法增强&#xff08;如&#xff1a;记录日志&#xff0c;添加事务&#xff0c;监控等&#xff09; 拿一…...

gif动画图像优化,相同的图在第2,4,6帧中重复出现,会增加图像体积吗?

对于 GIF 图像&#xff0c;情况与 Git 文件存储有所不同。GIF 是一种图像格式&#xff0c;其体积主要取决于图像的内容、颜色数量、优化设置等因素。如果在 GIF 动画中&#xff0c;相同的图像在第 2、4、6 帧中重复出现&#xff0c;是否会增加图像体积&#xff0c;取决于以下几…...

Harmony Next 跨平台开发入门

ArkUI-X 官方介绍 官方文档&#xff1a;https://gitee.com/arkui-x/docs/tree/master/zh-cn ArkUI跨平台框架(ArkUI-X)进一步将ArkUI开发框架扩展到了多个OS平台&#xff1a;目前支持OpenHarmony、Android、 iOS&#xff0c;后续会逐步增加更多平台支持。开发者基于一套主代码…...

阿里巴巴Qwen团队发布AI模型,可操控PC和手机

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

android 音视频系列引导

音视频这块的知识点自己工作中有用到&#xff0c;一直没有好好做一个总结&#xff0c;原因有客观和主观的。 客观是工作太忙&#xff0c;没有成段时间做总结。 主观自己懒。 趁着这次主动离职拿了n1的钱&#xff0c;休息一下&#xff0c;对自己的人生做一下总结&#xff0c;…...

STM32调试手段:重定向printf串口

引言 C语言中经常使用printf来输出调试信息&#xff0c;打印到屏幕。由于在单片机中没有屏幕&#xff0c;但是我们可以重定向printf&#xff0c;把数据打印到串口&#xff0c;从而在电脑端接收调试信息。这是除了debug外&#xff0c;另外一个非常有效的调试手段。 一、什么是pr…...

基于 Jenkins 的测试报告获取与处理并写入 Jira Wiki 的技术总结

title: 基于 Jenkins 的测试报告获取与处理并写入 Jira Wiki 的技术总结 tags: - jenkins - python categories: - jenkins在软件开发的持续集成与持续交付&#xff08;CI/CD&#xff09;流程里&#xff0c;及时、准确地获取并分析测试报告对保障软件质量至关重要。本文将详细…...

Vue.js组件开发-实现导出PDF文件可自定义添加水印及水印样式方向

使用 Vue 实现导出 PDF 文件并添加水印&#xff0c;同时支持设置水印样式、方向和自定义水印内容。 步骤 安装依赖&#xff1a;使用 html2canvas 将 HTML 内容转换为 canvas&#xff0c;使用 jspdf 生成 PDF 文件。创建 Vue 组件&#xff1a;在组件中实现水印生成、HTML 转 c…...

css中的animation

css的animation animation是一个综合属性,是animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, animation-play-state, and animation-timeline这些属性的简写 不过在…...

四.3 Redis 五大数据类型/结构的详细说明/详细使用( hash 哈希表数据类型详解和使用)

四.3 Redis 五大数据类型/结构的详细说明/详细使用&#xff08; hash 哈希表数据类型详解和使用&#xff09; 文章目录 四.3 Redis 五大数据类型/结构的详细说明/详细使用&#xff08; hash 哈希表数据类型详解和使用&#xff09;2.hash 哈希表常用指令(详细讲解说明)2.1 hset …...

基于Springboot + vue实现的洗衣店订单管理系统

“前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能学习网站” &#x1f496;学习知识需费心&#xff0c; &#x1f4d5;整理归纳更费神。 &#x1f389;源码免费人人喜…...

用 Scoop 优雅管理 Windows 软件:安装、配置与使用全指南

本篇将主要讲讲如何用「Scoop」优雅管理 Windows 软件&#xff1a;安装、配置与使用全指南 一、Scoop 是什么&#xff1f; Scoop 是一款专为 Windows 设计的命令行软件包管理工具&#xff0c;它能让你像 Linux 系统一样通过命令快速安装、更新和卸载软件。其核心优势包括&…...

深度学习中常用的评价指标方法

深度学习中常用的评价指标方法因任务类型&#xff08;如分类、回归、分割等&#xff09;而异。以下是一些常见的评价指标&#xff1a; 1. 分类任务 准确率&#xff08;Accuracy&#xff09; 定义&#xff1a;正确预测的样本数占总样本数的比例。 公式&#xff1a;AccuracyTPT…...

多协议网关BL110钡铼6路RS485转MQTT协议云网关

多协议网关BL110钡铼6路RS485转MQTT协议云网关是一款集成了多种通信协议的工业级网关设备&#xff0c;专为物联网&#xff08;IoT&#xff09;应用设计。该网关能够将RS485总线设备的数据转化为MQTT协议&#xff0c;通过网络传输到云平台&#xff0c;实现远程监控和数据管理。以…...

Nginx 安装配置指南

Nginx 安装配置指南 引言 Nginx 是一款高性能的 HTTP 和反向代理服务器&#xff0c;同时也可以作为 IMAP/POP3/SMTP 代理服务器。由于其稳定性、丰富的功能集以及低资源消耗而被广泛应用于各种场景。本文将为您详细介绍 Nginx 的安装与配置过程。 系统要求 在安装 Nginx 之…...

二叉树介绍

一.树的概念 树的图&#xff1a; 1.结点的度&#xff1a;一个结点含有子树的个数称为该结点的度&#xff1b; 如上图&#xff1a;A的度为6 2.树的度&#xff1a;一棵树中&#xff0c;所有结点度的最大值称为树的度&#xff1b; 如上图&#xff1a;树的度为6 3.叶子结点或终…...

VLC-Qt: Qt + libVLC 的开源库

参考链接 https://blog.csdn.net/u012532263/article/details/102737874...

【四川乡镇界面】图层shp格式arcgis数据乡镇名称和编码2020年wgs84无偏移内容测评

本文将详细解析标题和描述中提到的IT知识点&#xff0c;主要涉及GIS&#xff08;Geographic Information System&#xff0c;地理信息系统&#xff09;技术&#xff0c;以及与之相关的文件格式和坐标系统。 我们要了解的是"shp"格式&#xff0c;这是一种广泛用于存储…...

Helm Chart 详解:从入门到精通

Helm 是 Kubernetes 的包管理工具,而 Helm Chart 是 Helm 的核心概念,用于定义、安装和升级 Kubernetes 应用。本文将详细介绍 Helm Chart 的结构、核心文件及其作用,帮助你从入门到精通 Helm Chart。 © ivwdcwso (ID: u012172506) 1. 什么是 Helm Chart? Helm Char…...

excel如何查找一个表的数据在另外一个表是否存在

比如“Sheet1”有“张三”、“李四”“王五”三个人的数据&#xff0c;“Sheet2”只有“张三”、“李四”的数据。我们通过修改“Sheet1”的“民族”或者其他空的列&#xff0c;修改为“Sheet2”的某一列。这样修改后筛选这个修改的列为空的或者为出错的&#xff0c;就能找到两…...

gesp(C++六级)(7)洛谷:P10376:[GESP202403 六级] 游戏

gesp(C六级)&#xff08;7&#xff09;洛谷&#xff1a;P10376&#xff1a;[GESP202403 六级] 游戏 题目描述 你有四个正整数 n , a , b , c n,a,b,c n,a,b,c&#xff0c;并准备用它们玩一个简单的小游戏。 在一轮游戏操作中&#xff0c;你可以选择将 n n n 减去 a a a&am…...

随机森林例子

完整代码&#xff1a; # 导入必要的库 from sklearn.datasets import load_iris from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import numpy as np# 加载鸢尾花数…...

Qt中Widget及其子类的相对位置移动

Qt中Widget及其子类的相对位置移动 最后更新日期&#xff1a;2025.01.25 下面让我们开始今天的主题… 一、开启篇 提出问题&#xff1a;请看上图&#xff0c;我们想要实现的效果是控件黄色的Widge&#xff08;m_infobarWidget&#xff09;t随着可视化窗口&#xff08;m_glWidge…...

MyBatis 关联映射详解

目录 一、创建表结构 1. 学生表 (student) 2. 教师表 (teacher) 二、一对一 & 多对一 关系映射 1. 连表查询&#xff08;直接查询&#xff09; 2. 分步查询&#xff08;懒加载&#xff09; 三、一对多 关系映射 1. 直接查询 2. 分步查询 四、MyBatis 延迟加载&am…...

Shell特殊位置变量以及常用内置变量总结

目录 1. 特殊的状态变量 1.1 $?&#xff08;上一个命令的退出状态&#xff09; 1.2 $$&#xff08;当前进程的 PID&#xff09; 1.3 $!&#xff08;后台进程的 PID&#xff09; 1.4 $_&#xff08;上一条命令的最后一个参数&#xff09; 2.常用shell内置变量 2.1 echo&…...

LeetCode:96.不同的二叉搜索树

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;96.不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉…...