跳过正文
  1. 文章/

C# 学习加固笔记(二):函数与结构体

Lickba
作者
Lickba
热爱游戏,也喜欢记录创作过程与踩过的坑。
C# 学习加固 - 这篇文章属于一个选集。
§ 2: 本文

这是「C# 学习加固」系列的第 2 篇,共 5 篇;可通过文末的系列导航继续阅读。

18. 函数的基本使用
#

函数的基本使用
#

函数一般也叫方法,将可以复用的代码包装起来,方便之后调用

C# 函数的定义与调用结构

private void Start()
{
    int num = 100;
    Function(num,"Test"); //调用函数
    Debug.Log($"实参num = {num}"); //输出 num 的值

    int num2 = 33;
    num2 = Add(num2, 333);
    Debug.Log($"Add(100, 333) = {num2}"); // 输出 Add 函数的返回值

}

// 函数的参数名称理论是无所谓是什么的,但是还是要见名知意
// 函数的参数叫做形参,也就是形式参数,和外部调用处的函数变量名称没有关系
// 实参和形参没有关系:一方改变不影响另外一方,相当于变成了两个类型一致但是数值没有关联的变量
void Function(int num,string info)
{
    num += 200;
    for (int i = 0; i <= 100; i++)
    {
        //Debug.Log($"{i}");
    }
    Debug.Log($"形参num : {num}");
}

// 一个返回值类型为int的函数
int Add(int a, int b)
{
    int res = a + b;
    return res; // return的结果要跟函数的返回值类型一致
}
void Do()
{
	return; //return意味着不执行之后的逻辑
}

19. 函数重载
#

同名函数不同参数称之为重载

private void Start()
{
    int res = Add(1, 2);
    int res2 = Add(1, 2, 3);
    int res3 = Add(1, "2");
}

int Add(int a, int b)
{
    int res = a + b;
    return res; // return的结果要跟函数的返回值类型一致
}

// int.Parse:转为int类型
int Add(int a, string b)
{
    int res = a + int.Parse(b);
    return res;
}

int Add(int a, int b, int c)
{
    int res = a + b + c;
    return res;
}

20. 函数的ref和out关键字
#

ref:通常情况下,形参和实参只是值一样,但是并不是同一个变量。如果通过ref则可以视为一个变量

out:函数的返回值只有一个,如果希望有两个及以上,则可以使用

函数的参数可以有默认值,在定义的时候直接=即可

private void Start()
{
    int a = 3;
    RefFunction(ref a);    // 实参
    Debug.Log($"实参: {a}");

    // 需求:
    // 1.请求登录,提供一个账号
    ///2.如果有此账号,返回true,并且返回密码
    if (CheckLogin("user123", out string password)) // 相当于定义在if的外面
    {
        Debug.Log($"登录成功,密码是:{password}");
    }
    else
    {
        Debug.Log("登录失败,账号不存在");
    }

    TestFunction(100,200);
    TestFunction(10);
    TestFunction(1);
}

void RefFunction(ref int a)    // 形参
{
    a += 1000;
    Debug.Log($"形参: {a}");
}

/// <summary>
/// 检查登录
/// </summary>
/// <param name="account">用户名</param>
/// <param name="password">密码</param>
/// <returns>是否登录成功</returns>
bool CheckLogin(string account, out string password)
{
    // 模拟账号和密码
    if (account == "user123")
    {
        password = "password123"; // 返回密码
        return true; // 登录成功
    }
    else
    {
        password = null; // 无效账号
        return false; // 登录失败
    }
}

// 测试可选参数(默认参数)
// 如果你传递,则使用传递的值;如果不传递,则使用默认值
void TestFunction(int c,int a = 10099, int b = 9999)
{
    Debug.Log(a+b+c);
}

21. 结构体
#

结构体是一种自定义类型,用于创建我们游戏或者实际业务中的自定义类型

比如Moba游戏中的英雄角色,那必然存在英雄的血量、攻击力、等级等关键属性,这些属性我们可以用int、float等类型来描述,但是往往我们需要打包来使用,因为我们往往需要“这个英雄的攻击力”、“这个英雄的防御力”、我们会可以抽象出“英雄”这个数据概念。所以我们可以创建一个“英雄类型”。

同时也为我们之后学习非常重要的“类”做一个铺垫

using UnityEngine;

public class Hello : MonoBehaviour
{
    private void Start()
    {
        Hero tanke = new Hero(); // 构造一个结构体
        tanke.Name = "超级坦克"; // 修改结构体的成员变量
        Debug.Log($"英雄: {tanke.Name}");
        tanke.Show(); // 调用结构体的成员函数

        Hero tanke2 = new Hero("X刺客", 30, 500); // 构造另一个结构体
        tanke2.Show(); // 调用另一个结构体的成员函数
    }

}
/// <summary>
/// 英雄结构体
/// </summary>
struct Hero
{
    // 成员
    // 成员字段(变量)
    // 访问修饰符
    // 1. public: 公共的,可以被外部访问
    // 2. private: 私有的,只能在结构体内部访问
    public string Name; // 默认值是 null
    public int Attack;  // 成员存在默认值,数值类型(int, float, double)默认值是 0
    public int Hp;

    // 默认有一个无参构造函数
    // 构造函数
    public Hero(string name, int attack, int hp)
    {
        Name = name;
        Attack = attack;
        Hp = hp;
    }

    // 成员函数
    public void Show()
    {
        Debug.Log($"英雄: {Name}, 攻击力: {Attack}, 生命值: {Hp}");
    }
}

22. 结构体使用细节
#

  1. 构造函数也可以重载

  2. this关键字

    代表着当前对象,也就是在外部声明的变量

  3. 访问修饰符详解

    private修饰的成员外界无法访问,只能在结构体内部使用

    public修饰的成员,外界和内部都可以随意使用

using UnityEngine;

public class Hello : MonoBehaviour
{
    private void Start()
    {
        Hero tanke2 = new Hero("X刺客", 30, 500); // 构造另一个结构体
        tanke2.Show(); // 调用另一个结构体的成员函数

        HeroClass mage = new HeroClass("法师", 50); // 构造一个类
        mage.Show(); // 调用类的成员函数
        // 结构体和类的区别
        // 1. 结构体是值类型,类是引用类型
        // 2. 结构体的实例在栈上分配内存,类的实例在堆上分配内存
        // 3. 结构体的实例在赋值时会复制所有成员,类的实例在赋值时只复制引用
        // 4. 结构体不能继承其他结构体或类,但可以实现接口
    }
}
/// <summary>
/// 英雄结构体
/// </summary>
struct Hero
{
    // 成员
    // 成员字段(变量)
    // 访问修饰符
    // 1. public: 公共的,可以被外部访问
    // 2. private: 私有的,只能在结构体内部访问
    public string Name; // 默认值是 null
    public int Attack;  // 成员存在默认值,数值类型(int, float, double)默认值是 0
    public int Hp;

    // 默认有一个无参构造函数
    // 构造函数
    public Hero(string Name, int attack, int hp)
    {
        // 同名变量的就近原则,就近:定义的位置
        Name = Name;
        this.Name = Name; // this 关键字指代当前结构体实例
        Attack = attack;
        Hp = hp;
    }

    public Hero(string name,int attack, int hp,int attackBuff)
    {
        Name = name;
        Hp = hp;
        Attack = attack + attackBuff; // 攻击力加上攻击增益
    }

    // 成员函数
    public void Show()
    {
        Debug.Log($"英雄: {Name}, 攻击力: {Attack}, 生命值: {Hp}");
    }

}

/// <summary>
/// 英雄类
/// </summary>
public class HeroClass
{
    public string Name;
    public int Attack;

    public HeroClass(string name, int attack)
    {
        Name = name;
        Attack = attack;
    }
    public void Show()
    {
        Debug.Log($"英雄: {Name}, 攻击力: {Attack}");
    }
}
C# 学习加固 - 这篇文章属于一个选集。
§ 2: 本文