C# 结构体

文章目录

  • 前言
  • 一、结构体的定义与基本使用
    • (一)定义结构体
    • (二)结构体的使用示例
  • 二、C# 结构的特点
    • (一)丰富的成员类型
    • (二)构造函数相关限制与特性
    • (三)继承方面的限制
    • (四)接口实现能力
    • (五)成员修饰符限制
    • (六)实例化与初始化特点
    • (七)内存分配与性能特点
    • (八)可变性特点
  • 三、类 vs 结构
    • (一)值类型 vs 引用类型
    • (二)继承和多态性
    • (三)默认构造函数
    • (四)赋值行为
    • (五)传递方式
    • (六)可空性
    • (七)性能和内存分配


前言

  结构体(struct)是一种极为重要的值类型(value type)数据结构,能够将各种相关的数据有条理地组织并存储起来,为我们处理和操作数据提供了一种高效且灵活的方式。
在这里插入图片描述

一、结构体的定义与基本使用

(一)定义结构体

  在 C# 里,我们使用 struct 关键字来创建结构体。struct 语句的作用就像是为程序打造了一个带有多个成员的全新数据类型模板,通过它可以定义出符合特定需求的数据结构。例如,当我们想要跟踪图书馆中书的各种相关信息时,就可以定义一个名为 Books 的结构体来承载这些信息。
如下所示:

struct Books
{
    public string title;
    public string author;
    public string subject;
    public int book_id;
};

  在这个 Books 结构体的定义中,包含了表示书籍标题(title)、作者(author)、主题(subject)以及书籍编号(book_id)的成员变量,它们的类型分别为 string 和 int,通过这些成员变量,我们能够全面地描述一本书的关键属性。

(二)结构体的使用示例

以下是一个展示结构体用法的完整程序示例:

using System;
using System.Text;

struct Books
{
    public string title;
    public string author;
    public string subject;
    public int book_id;
};

public class testStructure
{
    public static void Main(string[] args)
    {
        // 声明两个 Books 类型的结构体变量 Book1 和 Book2
        Books Book1;        /* 声明 Book1,类型为 Books */
        Books Book2;        /* 声明 Book2,类型为 Books */

        // 为 Book1 的各个成员变量赋值,详细描述一本书的信息
        Book1.title = "C Programming";
        Book1.author = "Nuha Ali";
        Book1.subject = "C Programming Tutorial";
        Book1.book_id = 6495407;

        // 同样地,为 Book2 赋值,描述另一本书的情况
        Book2.title = "Telecom Billing";
        Book2.author = "Zara Ali";
        Book2.subject = "Telecom Billing Tutorial";
        Book2.book_id = 6495700;

        // 打印 Book1 的详细信息
        Console.WriteLine("Book 1 title : {0}", Book1.title);
        Console.WriteLine("Book 1 author : {0}", Book1.author);
        Console.WriteLine("Book 1 subject : {0}", Book1.subject);
        Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);

        // 打印 Book2 的详细信息
        Console.WriteLine("Book 2 title : {0}", Book2.title);
        Console.WriteLine("Book 2 author : {0}", Book2.author);
        Console.WriteLine("Book 2 subject : {0}", Book2.subject);
        Console.WriteLine("Book 2 book_id : {0}", Book2.book_id);

        Console.ReadKey();
    }
}

当上述代码被编译并执行后,会输出如下结果:

Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

  从这个示例可以清晰地看到,我们通过结构体变量能够方便地访问和操作其内部的各个成员变量,分别对不同的书籍信息进行赋值和展示,就像使用自定义的数据类型一样自然流畅,这充分体现了结构体在组织和管理相关数据方面的便利性。

二、C# 结构的特点

(一)丰富的成员类型

  结构体并非仅仅局限于存储简单的数据,它还具备很强的扩展性,可以带有方法、字段、索引、属性、运算符方法和事件等多种成员类型。这使得结构体能够适用于表示各种各样的轻量级数据情况,例如坐标(可以通过包含 x 和 y 坐标值的结构体,并搭配相应的方法来进行坐标运算等操作)、范围(定义包含起始值和结束值的结构体,以及判断是否包含某个值的方法等)、日期、时间等。

(二)构造函数相关限制与特性

  结构体可以定义构造函数,不过需要注意的是,它不能定义析构函数。而且,结构体不能定义无参构造函数,这一点与类有着明显的区别。在结构体中,无参构造函数(默认)是由系统自动定义的,并且这个默认的无参构造函数不能被我们手动改变。
例如:

struct Point
{
    public int X;
    public int Y;
    // 合法的有参构造函数
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
    // 以下是非法的无参构造函数定义,结构体不允许这样写
    // public Point()
    // {
    // }
}

(三)继承方面的限制

  与类不同的是,结构体不能继承其他的结构或类,也不能作为其他结构或类的基础结构。这意味着结构体在继承体系方面相对独立,它更侧重于简单地封装和处理自身内部定义的数据和相关逻辑,而不像类那样可以通过继承来扩展功能、实现多态等复杂的面向对象设计模式。

(四)接口实现能力

  虽然结构体不能参与继承关系,但它具备实现一个或多个接口的能力。通过实现接口,结构体可以遵循接口中定义的契约,提供特定的方法实现,从而在一定程度上增强了结构体与其他代码模块之间的交互性和通用性,使其能够更好地融入到面向对象的编程框架中。例如:

interface IPrintable
{
    void Print();
}

struct Document : IPrintable
{
    public string Content;
    public void Print()
    {
        Console.WriteLine(Content);
    }
}

  在这个示例中,Document 结构体实现了 IPrintable 接口,并重写了 Print 方法,这样就可以按照接口定义的规范来输出结构体中存储的文档内容,实现了特定的功能需求。

(五)成员修饰符限制

  结构体成员不能指定为 abstract、virtual 或 protected。这是因为结构体本身的设计初衷是用于表示简单、轻量级的数据结构,避免了像类那样复杂的多态和继承相关的特性,所以这些与类的高级面向对象特性相关的修饰符在结构体中是不适用的。

(六)实例化与初始化特点

  当我们使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。不过,结构体有一个很独特的地方,那就是它可以不使用 New 操作符即可被实例化。但如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才能够被正常使用。例如:

struct SimpleStruct
{
    public int Value;
}

class Program
{
    static void Main()
    {
        SimpleStruct struct1;
        // 以下这种不使用 New 操作符的方式,需要先初始化字段
        struct1.Value = 10;
        // 此时 struct1 才能正常使用,比如进行后续操作

        SimpleStruct struct2 = new SimpleStruct();
        // 使用 New 操作符创建结构体对象,字段会按照构造函数或默认规则初始化
    }
}

(七)内存分配与性能特点

  结构体变量通常分配在栈上,这是结构体在内存管理方面的一个重要特性。由于栈内存的分配和释放速度相对较快,所以结构体在创建和销毁时往往比类更加高效,使得它们在性能上具有一定的优势,尤其适用于那些需要频繁创建和销毁的简单数据对象场景。然而,如果将结构用作类的字段,且这个类是引用类型,那么此时结构将存储在堆上,这是因为类的对象本身存储在堆上,其内部包含的结构体字段也会随之存储在堆中。

(八)可变性特点

  结构体默认情况下是可变的,这意味着我们可以直接修改它们的字段值。
例如:

struct MutableStruct
{
    public int Data;
}

class Program
{
    static void Main()
    {
        MutableStruct struct1 = new MutableStruct();
        struct1.Data = 5;
        // 可以成功修改结构体的字段值
    }
}

  但如果我们将结构定义为只读(通过将结构体的成员设置为只读属性等方式来实现),那么它的字段将是不可变的,这样可以保证结构体在使用过程中的数据稳定性,避免意外的修改。

三、类 vs 结构

  在 C# 编程中,类和结构虽然都用于构建对象、组织数据和实现功能,但它们在设计和使用上有着诸多不同的考虑因素,各自适用于不同的编程场景。

(一)值类型 vs 引用类型

  结构体是值类型(Value Type):结构体作为值类型,其内存分配是在栈上进行的(特殊情况下如作为类的字段会存储在堆上)。当我们将结构实例传递给方法或者赋值给另一个变量时,会复制整个结构的内容,这就相当于创建了一个全新的、独立的副本。
例如:

struct MyStruct
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        MyStruct structInstance1 = new MyStruct { X = 1, Y = 2 };
        MyStruct structInstance2 = structInstance1;
        structInstance1.X = 5;
        Console.WriteLine($"Struct: {structInstance1.X}, {structInstance2.X}");
    }
}

  在上述代码中,修改 structInstance1 的 X 值并不会影响 structInstance2 的 X 值,因为它们是两个独立的副本。
  类是引用类型(Reference Type):类作为引用类型,其内存分配是在堆上完成的。当把类实例传递给方法或者赋值给另一个变量时,实际上传递的是引用(也就是内存地址),而并非整个对象的副本。这意味着多个变量可能指向同一个对象,对其中一个变量所做的修改会影响到其他指向该对象的变量。
例如:

class MyClass
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        MyClass classInstance1 = new MyClass { X = 3, Y = 4 };
        MyClass classInstance2 = classInstance1;
        classInstance1.X = 6;
        Console.WriteLine($"Class: {classInstance1.X}, {classInstance2.X}");
    }
}

  在这个例子中,修改 classInstance1 的 X 值后,classInstance2 的 X 值也会随之改变,因为它们都指向堆上的同一个对象。

(二)继承和多态性

  • 结构不能继承: 结构体无法继承其他结构或类,也不能作为其他结构或类的基类,它在继承体系方面相对封闭,主要聚焦于自身内部的数据封装和简单操作逻辑。
    例如,以下代码是非法的:
struct MyStruct
{
    // 结构不能继承,以下代码会报错
    // struct MyDerivedStruct : MyBaseStruct
    // {
    // }
}
  • 类支持继承: 类则具备强大的继承和多态性支持,我们可以通过派生新类来扩展现有类的功能,实现代码的复用和面向对象设计中的多态效果。
    例如:
class MyBaseClass
{
    public virtual void DoSomething()
    {
        Console.WriteLine("Base class method");
    }
}

class MyDerivedClass : MyBaseClass
{
    public override void DoSomething()
    {
        Console.WriteLine("Derived class method");
    }
}

class Program
{
    static void Main()
    {
        MyBaseClass instance = new MyDerivedClass();
        instance.DoSomething();
    }
}

  在上述代码中,MyDerivedClass 继承自 MyBaseClass,并重写了 DoSomething 方法,通过多态机制,根据对象的实际类型来决定调用哪个类的 DoSomething 方法,展示了类在继承和多态方面的强大功能。

(三)默认构造函数

  • 结构不能有无参数的构造函数: 结构体不允许包含无参数的构造函数,只能定义有参数的构造函数来对结构体的成员进行初始化。例如:
struct MyStruct
{
    public int X;
    public int Y;
    // 以下是非法的无参构造函数定义,结构体不允许这样写
    // public MyStruct()
    // {
    // }
    public MyStruct(int x, int y)
    {
        X = x;
        Y = y;
    }
}
  • 类可以有无参数的构造函数: 类不仅可以包含有参数的构造函数,还可以有无参数的构造函数。如果在类的定义中没有提供任何构造函数,系统会自动提供一个默认的无参数构造函数,方便类的实例化。例如:
class MyClass
{
    public int X;
    public int Y;
    // 合法的无参数构造函数定义
    public MyClass()
    {
    }
    public MyClass(int x, int y)
    {
        X = x;
        Y = y;
    }
}

(四)赋值行为

  • 类型为类的变量在赋值时存储的是引用: 当对类类型的变量进行赋值操作时,实际上只是复制了对象的引用,所以两个变量会指向同一个对象。例如:
class MyClass
{
    public int Value;
}

class Program
{
    static void Main()
    {
        MyClass obj1 = new MyClass { Value = 10 };
        MyClass obj2 = obj1;
        obj2.Value = 20;
        Console.WriteLine($"obj1.Value: {obj1.Value}");
    }
}

  在上述代码中,修改 obj2 的 Value 值后,obj1 的 Value 值也会变为 20,因为它们指向同一个对象。
  结构变量在赋值时会复制整个结构:而对于结构体变量,赋值操作会复制整个结构的内容,每个变量都拥有自己独立的副本,相互之间不会产生影响。例如:

struct MyStruct
{
    public int Value;
}

class Program
{
    static void Main()
{
        MyStruct struct1 = new MyStruct { Value = 10 };
        MyStruct struct2 = struct1;
        struct1.Value = 20;
        Console.WriteLine($"struct1.Value: {struct1.Value}, struct2.Value: {struct2.Value}");
    }
}

  在这个例子中,修改 struct1 的 Value 值并不会改变 struct2 的 Value 值,因为它们是各自独立的结构副本。

(五)传递方式

  • 类型为类的对象在方法调用时通过引用传递: 在方法调用过程中,传递类类型的对象时,传递的是对象的引用,这就意味着在方法内部对该对象所做的任何更改都会影响到原始对象。例如:
class MyClass
{
    public int Value;
}

class Program
{
    static void ModifyClassObject(MyClass obj)
    {
        obj.Value = 30;
    }

    static void Main()
    {
        MyClass myObj = new MyClass { Value = 20 };
        ModifyClassObject(myObj);
        Console.WriteLine($"myObj.Value: {myObj.Value}");
    }
}

  在上述代码中,在 ModifyClassObject 方法中修改了传入对象的 Value 值后,回到 Main 方法中,原始的 myObj 对象的 Value 值也已经被改变了。
  结构对象通常通过值传递:而对于结构体对象,在方法调用时传递的是结构的副本,并非原始的结构对象本身,所以在方法中对结构所做的更改不会影响到原始对象。例如:

struct MyStruct
{
    public int Value;
}

class Program
{
    static void ModifyStructObject(MyStruct structObj)
    {
        structObj.Value = 40;
    }

    static void Main()
    {
        MyStruct myStruct = new MyStruct { Value = 30 };
        ModifyStructObject(myStruct);
        Console.WriteLine($"myStruct.Value: {myStruct.Value}");
    }
}

  在这个例子中,尽管在 ModifyStructObject 方法中修改了传入的结构体对象的 Value 值,但回到 Main 方法中,原始的 myStruct 对象的 Value 值并没有改变,因为传递的只是副本。

(六)可空性

  • 结构体是值类型,不能直接设置为 null: 由于 null 是引用类型的默认值,而不是值类型的默认值,所以结构体本身不能直接被赋值为 null。但如果我们需要表示结构体变量的缺失或无效状态,可以借助 Nullable(也可写成 T?)这种可空类型来实现。例如,假设有一个表示学生成绩的结构体,有时候成绩可能还未录入(即无效状态),就可以这样定义:
struct StudentScore
{
    public int? MathScore;
    public int? EnglishScore;
}

class Program
{
    static void Main()
    {
        StudentScore score = new StudentScore();
        score.MathScore = null;
        score.EnglishScore = 80;

        if (score.MathScore.HasValue)
        {
            Console.WriteLine($"数学成绩为: {score.MathScore.Value}");
        }
        else
        {
            Console.WriteLine("数学成绩尚未录入");
        }

        Console.WriteLine($"英语成绩为: {score.EnglishScore}");
    }
}

  在上述代码中,通过使用 int? 类型来定义结构体中的成绩成员变量,就能灵活地表示成绩存在或缺失的不同状态了。
类默认可为 null:类作为引用类型,其实例默认是可以为 null 的。这意味着在声明一个类类型的变量时,如果没有对其进行实例化赋值,它的值就是 null,表示该变量目前没有指向任何实际的对象。例如:

class Person
{
    public string Name;
}

class Program
{
    static void Main()
    {
        Person person;
        if (person == null)
        {
            Console.WriteLine("person 变量目前未指向任何对象");
        }

        person = new Person { Name = "John" };
        Console.WriteLine($"这个人的名字是: {person.Name}");
    }
}

  在这个例子中,一开始声明 person 变量时它的值为 null,直到后续通过 new 操作符创建了 Person 类的实例并赋值给它,才使其指向了一个实际的对象。

(七)性能和内存分配

  • 结构通常更轻量: 由于结构体是值类型且大多在栈上分配内存,相比于类,它们通常更加轻量级。在处理一些简单的数据表示场景时,结构体能够减少内存开销,并且在创建和销毁对象时,因为栈内存操作的高效性,速度也更快。例如,在一个游戏中表示角色的坐标信息,如果使用结构体来存储 (x, y) 坐标,大量创建和更新这些坐标结构体对象时,相较于使用类来存储,在性能和内存占用方面往往更有优势。
  • 类可能有更多开销: 类作为引用类型,存储在堆上,其内存管理相对复杂一些,可能涉及到更多的内存开销,比如对象的引用计数、垃圾回收等机制都会带来一定的性能损耗。而且在创建类对象时,需要在堆上分配内存空间,这个过程相对栈上分配会更耗时一些。不过,类的这种设计也使得它能够处理更复杂的对象关系、实现继承和多态等高级功能,适用于构建大型、复杂的软件系统中的各种对象模型。
      以下通过一个综合示例再次对比类和结构在上述各方面的不同表现:
using System;

// 结构声明
struct MyStruct
{
    public int X;
    public int Y;

    // 有参数的构造函数
    public MyStruct(int x, int y)
    {
        X = x;
        Y = y;
    }
}

// 类声明
class MyClass
{
    public int X;
    public int Y;

    // 类可以有无参数的构造函数
    public MyClass()
    {
    }

    // 有参数的构造函数
    public MyClass(int x, int y)
    {
        X = x;
        Y = y;
    }
}

class Program
{
    static void Main()
    {
        // 结构是值类型,分配在栈上
        MyStruct structInstance1 = new MyStruct(1, 2);
        MyStruct structInstance2 = structInstance1; // 复制整个结构

        // 类是引用类型,分配在堆上
        MyClass classInstance1 = new MyClass(3, 4);
        MyClass classInstance2 = classInstance1; // 复制引用,指向同一个对象

        // 修改结构实例不影响其他实例
        structInstance1.X = 5;
        Console.WriteLine($"Struct: {structInstance1.X}, {structInstance2.X}");

        // 修改类实例会影响其他实例
        classInstance1.X = 6;
        Console.WriteLine($"Class: {classInstance1.X}, {classInstance2.X}");

        // 演示结构体不能有无参数构造函数
        // MyStruct structNoParam = new MyStruct(); // 编译会报错

        // 演示类可以有无参数构造函数
        MyClass classNoParam = new MyClass();

        // 演示结构体不能继承
        // struct MyDerivedStruct : MyStruct // 编译会报错
        // {
        // }

        // 演示类支持继承
        class MyDerivedClass : MyClass
        {
        }

        // 演示结构体变量赋值是复制整个结构
        MyStruct structCopy = new MyStruct(7, 8);
        MyStruct structCopy2 = structCopy;
        structCopy.X = 9;
        Console.WriteLine($"Struct Copy: {structCopy.X}, {structCopy2.X}");

        // 演示类变量赋值是复制引用
        MyClass classCopy = new MyClass(10, 11);
        MyClass classCopy2 = classCopy;
        classCopy.X = 12;
        Console.WriteLine($"Class Copy: {classCopy.X}, {classCopy2.X}");

        // 演示结构体在方法调用时通过值传递,方法内修改不影响原始对象
        MyStruct structForMethod = new MyStruct(13, 14);
        ModifyStruct(structForMethod);
        Console.WriteLine($"Struct in Method: {structForMethod.X}");

        // 演示类在方法调用时通过引用传递,方法内修改影响原始对象
        MyClass classForMethod = new MyClass(15, 16);
        ModifyClass(classForMethod);
        Console.WriteLine($"Class in Method: {classForMethod.X}");
    }

    static void ModifyStruct(MyStruct structObj)
    {
        structObj.X = 17;
    }

    static void ModifyClass(MyClass classObj)
    {
        classObj.X = 18;
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Easyexcel(7-自定义样式)

相关文章链接 Easyexcel(1-注解使用)Easyexcel(2-文件读取)Easyexcel(3-文件导出)Easyexcel(4-模板文件)Easyexcel(5-自定义列宽)Easyexcel(6-单…

【c语言】文件操作详解 - 从打开到关闭

文章目录 1. 为什么使用文件?2. 什么是文件?3. 如何标识文件?4. 二进制文件和文本文件?5. 文件的打开和关闭5.1 流和标准流5.1.1 流5.1.2 标准流 5.2 文件指针5.3 文件的打开和关闭 6. 文件的读写顺序6.1 顺序读写函数6.2 对比一组…

2024-11-23 队列及顺序存储实现

2.3.1 队列及顺序存储实现 与堆栈类似,队列也是一种受限制的线性表。 其实我们在日常生活中经常会碰到排队。我们来观察一下,什么叫做队列,里面有两个最基本的操作,一个叫做入队,一个叫做出队。也就是你能加入这个队…

卷积神经网络学习记录

目录 神经网络基础定义: 基本组成部分 工作流程 卷积层(卷积定义)【CONV】: 卷积层(Convolutional Layer) 特征提取:卷积层的主要作用是通过卷积核(或滤波器)运算提…

数据结构初阶---复杂度

一、数据结构前言 1.数据结构与算法 数据结构(Data Structure):是计算机组织、存储数据的一种方式,指相互之间存在一种或多种特定关系的数据元素的集合。 算法(Algorithm):就是定义良好的计算过程,他取一个或一组的值为输入&am…

二叉树的层次遍历

二叉树的层次遍历 题目 https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 描述 给你一个二叉树,请你返回其按 层次遍历 得到的节点值(即逐层地,从做到右访问所有节点) 代码实现 通过两个数组来交替打印 class Solution(object):def levelOrder

网络安全中的数据科学如何重新定义安全实践?

组织每天处理大量数据,这些数据由各个团队和部门管理。这使得全面了解潜在威胁变得非常困难,常常导致疏忽。以前,公司依靠 FUD 方法(恐惧、不确定性和怀疑)来识别潜在攻击。然而,将数据科学集成到网络安全中…

【Linux系统】—— 基本指令(四)

【Linux系统】—— 基本指令(三) 1「find」指令2 「grep」指令2.1 初识「grep」指令2.2 「grep」指令 选项 3 打包压缩基本知识4 「zip / unzip」指令5「tar」命令6 文件互传6.1 Linux 与 Windows 互传6.1.1 Linux向Windows传输6.1.2 Windows向Linux传输…

将django+vue项目发布部署到服务器

1.部署django后端服务 部署架构 1.1 下载依赖插件 pip3.8 freeze > requirements.txt1.2 安装依赖插件 pip3 install -r requirements.txt1.3 安装mysql数据库 apt install mysql-server初始化数据库 CREATE USER admin% IDENTIFIED WITH mysql_native_password BY 123…

网络层协议IP

对于网络层我们直接通过IP协议来了解其内容 一.IP协议 首先我们先来了解几个概念: 主机:配有IP地址,但是不进行路由控制的设备 路由器:配有IP地址,同时进行路由控制的设备 节点:主机和路由器的统称 所以现在…

AIGC-----AIGC在虚拟现实中的应用前景

AIGC在虚拟现实中的应用前景 引言 随着人工智能生成内容(AIGC)的快速发展,虚拟现实(VR)技术的应用也迎来了新的契机。AIGC与VR的结合为创造沉浸式体验带来了全新的可能性,这种组合不仅极大地降低了VR内容的…

如何利用 Puppeteer 的 Evaluate 函数操作网页数据

介绍 在现代的爬虫技术中,Puppeteer 因其强大的功能和灵活性而备受青睐。Puppeteer 是一个用于控制 Chromium 或 Chrome 浏览器的 Node.js 库,提供了丰富的 API 接口,能够帮助开发者高效地处理动态网页数据。本文将重点讲解 Puppeteer 的 ev…

【运维】 使用 shell 脚本实现类似 jumpserver 效果实现远程登录linux 服务器

实现效果 通过序号选择登录: 配置证书登录 配置证书登录可以免去每次都输入密码的麻烦。详见另一篇博文: 【ssh】使用秘钥对(公钥/私钥)登录linux主机以及原理介绍 自动登录脚本 直接复用以下脚本即可,在 server…

sqlmap学习,打靶sqli-labs.(1-19)

前言:用于学习sqlmap的简单使用,使用sqli-labs靶场进行测试。 当然,在实战中,考虑的更多,例如如何隐藏自己(特征码),编码加解密、sqlmap抓包调试分析等... 不过那些都是后话,太遥远...基础NO.1!! 先贴上我…

A045-基于spring boot的个人博客系统的设计与实现

🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹 赠送计算机毕业设计600…

[RabbitMQ] 保证消息可靠性的三大机制------消息确认,持久化,发送方确认

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…

Unity中动态生成贴图并保存成png图片实现

实现原理&#xff1a; 要生成长x宽y的贴图&#xff0c;就是生成x*y个像素填充到贴图中&#xff0c;如下图&#xff1a; 如果要改变局部颜色&#xff0c;就是从x1到x2(x1<x2),y1到y2(y1<y2)这个范围做处理&#xff0c; 或者要想做圆形就是计算距某个点&#xff08;x1,y1&…

sklearn学习

介绍&#xff1a;scaler&#xff1a;换算的意思 1. 归一化MinMaxScaler() 归一化的意思是将一堆数&#xff0c;如果比较离散&#xff0c;为了让数据更适合模型训练&#xff0c;将离散的数据压缩到0到1之间&#xff0c;以方便模型更高效优质的学习&#xff0c;而对数据的预处理…

windows下安装wsl的ubuntu,同时配置深度学习环境

写在前面&#xff0c;本次文章只是个人学习记录&#xff0c;不具备教程的作用。个别信息是网上的&#xff0c;我会标注&#xff0c;个人是gpt生成的 安装wsl 直接看这个就行&#xff1b;可以不用备份软件源。 https://blog.csdn.net/weixin_44301630/article/details/1223900…

Flutter:启动屏逻辑处理02:启动页

启动屏启动之后&#xff0c;制作一个启动页面 新建splash&#xff1a;view 视图中只有一张图片sliding.png就是我们的启动图 import package:flutter/material.dart; import package:get/get.dart; import index.dart; class SplashPage extends GetView<SplashController…