第7篇:方法封装——复用代码

**作者:**中文编程倡导者—— 李金雨
联系方式: wbtm2718@qq.com
**目标读者:**编程入门(零基础)
核心理念: 使用华为仓颉原生中文编程,体验真正的国产编程语言


一、开篇引入

1.1 生活中的"功能"

想象你去餐厅吃饭:

  • 你想吃炒饭 → 叫厨师做
  • 你想喝果汁 → 叫服务员拿
  • 你想结账 → 叫收银员算账

你不用管炒饭怎么炒、果汁怎么榨,只需要"调用"他们的"功能"就行了!

1.2 程序中的"功能"

前面的课程,我们写了很多重复的代码:

// 计算第一个学生的BMI
let bmi1 = 体重1 / (身高1 * 身高1)

// 计算第二个学生的BMI
let bmi2 = 体重2 / (身高2 * 身高2)

// 计算第三个学生的BMI
let bmi3 = 体重3 / (身高3 * 身高3)

这样写太麻烦了! 我们可以把计算BMI的代码"封装"成一个"功能",用的时候直接调用:

// 定义功能
func 计算BMI(体重: Float64, 身高: Float64): Float64 {
    return 体重 / (身高 * 身高)
}

// 使用功能
let bmi1 = 计算BMI(体重1, 身高1)
let bmi2 = 计算BMI(体重2, 身高2)
let bmi3 = 计算BMI(体重3, 身高3)

1.3 关于方法定义的语法思考

在学习方法之前,我们再聊聊仓颉的语法设计。

仓颉的方法定义是:

func 计算BMI(体重: Float64, 身高: Float64): Float64 {
    return 体重 / (身高 * 身高)
}

这里又出现了类型后置的问题!

  • 参数类型后置:体重: Float64
  • 返回类型后置:: Float64

如果仓颉能像C#那样:

// C#风格
float 计算BMI(float 体重, float 身高) {
    return 体重 / (身高 * 身高);
}

这样读起来就是:

  • 浮点数 计算BMI(浮点数 体重, 浮点数 身高)”
  • 而不是:“计算BMI(体重 浮点数, 身高 浮点数) 浮点数

更符合中国人的定语前置习惯!

不过,func关键字表示"功能",还是比较直观的。而且方法名可以用中文,这一点很好!

1.4 本课目标

今天我们要学习:

  1. 什么是方法(功能)
  2. 如何定义方法
  3. 如何调用方法
  4. 参数和返回值
  5. 方法重载
  6. 做一个数学工具库

二、概念讲解

2.1 什么是方法?

定义

方法(函数)是一段可以重复使用的代码块,用来完成特定的任务。

就像乐高积木中的"标准件",做好了可以到处用!

生活例子:电饭煲的功能
电饭煲的功能:
┌─────────────────┐
│  功能:煮饭      │
│  输入:米、水    │
│  输出:米饭      │
└─────────────────┘

┌─────────────────┐
│  功能:煮粥      │
│  输入:米、水    │
│  输出:粥        │
└─────────────────┘

2.2 定义方法

基本语法
func 方法名(参数1: 类型, 参数2: 类型): 返回类型 {
    // 方法代码
    return 返回值
}

再次吐槽类型后置

部分 说明 问题
func 关键字,表示定义功能 ✅ 比较好理解
方法名 方法的名字 ✅ 可以用中文
参数: 类型 输入的数据 ❌ 类型后置
: 返回类型 输出数据的类型 ❌ 类型后置
return 返回结果 ✅ 国际通用

如果改进成类型前置:

// 设想中的改进
Float64 计算BMI(Float64 体重, Float64 身高) {
    return 体重 / (身高 * 身高)
}

这样读起来就是"浮点数 计算BMI(浮点数 体重, 浮点数 身高)",更符合中文习惯!

简单例子:打招呼
// 定义方法
func 打招呼(名字: String): String {
    return "你好," + 名字 + "!"
}

// 使用
main() {
    let 问候语1 = 打招呼("张三")    // "你好,张三!"
    let 问候语2 = 打招呼("李四")    // "你好,李四!"
    
    println(问候语1)
    println(问候语2)
}

2.3 调用方法

什么是调用?

调用就是使用定义好的方法。

就像你做好了电饭煲,要按"煮饭"按钮才能煮饭。

调用语法
方法名(参数1, 参数2, ...)

2.4 不同类型的方法

类型1:有参数有返回值(最常用)
func 计算圆面积(半径: Float64): Float64 {
    return 3.14159 * 半径 * 半径
}

let 面积 = 计算圆面积(5.0)    // 78.54
类型2:有参数无返回值
func 显示问候(名字: String): Unit {
    println("你好," + 名字)
    // 没有return
}

显示问候("张三")    // 输出:你好,张三
类型3:无参数有返回值
func 获取当前时间(): String {
    // 返回当前时间字符串
    return "2024-01-15 14:30:00"
}

let 时间 = 获取当前时间()
类型4:无参数无返回值
func 显示欢迎信息(): Unit {
    println("欢迎使用本应用!")
    println("请遵守使用规则")
}

显示欢迎信息()

2.5 方法的好处

好处1:代码复用
// 不用方法:重复写3次
let 面积1 = 3.14159 * 半径1 * 半径1
let 面积2 = 3.14159 * 半径2 * 半径2
let 面积3 = 3.14159 * 半径3 * 半径3

// 用方法:调用3次
let 面积1 = 计算圆面积(半径1)
let 面积2 = 计算圆面积(半径2)
let 面积3 = 计算圆面积(半径3)
好处2:易于维护

如果要修改计算方式,只需要改一处:

// 修改前:用3.14159
func 计算圆面积(半径: Float64): Float64 {
    return 3.14159 * 半径 * 半径
}

// 修改后:用更精确的π值
func 计算圆面积(半径: Float64): Float64 {
    return 3.14159265359 * 半径 * 半径
}
// 所有调用的地方都自动更新了!

三、动手实践

3.1 基础练习:数学工具库

// 数学工具库

main() {
    println("=== 数学工具库 ===")
    println("")
    
    // 测试计算BMI
    let 体重: Float64 = 60.0
    let 身高: Float64 = 1.75
    let bmi = 计算BMI(体重, 身高)
    println("体重${体重}kg,身高${身高}m")
    println("BMI:${bmi}")
    println("体重状态:${判断体重状态(bmi)}")
    
    println("")
    
    // 测试圆面积
    let 半径: Float64 = 5.0
    let 面积 = 计算圆面积(半径)
    println("半径:${半径}")
    println("圆面积:${面积}")
    
    println("")
    
    // 测试最大值最小值
    let 甲: Int64 = 10
    let 乙: Int64 = 20
    let 丙: Int64 = 15
    println("${甲}、${乙}、${丙}中的最大值:${求最大值(甲, 乙, 丙)}")
    println("${甲}、${乙}、${丙}中的最小值:${求最小值(甲, 乙, 丙)}")
    
    println("")
    
    // 测试随机数
    println("1-100之间的随机数:${生成随机数(1, 100)}")
}

// 计算BMI
func 计算BMI(体重: Float64, 身高: Float64): Float64 {
    return 体重 / (身高 * 身高)
}

// 判断体重状态
func 判断体重状态(bmi: Float64): String {
    if (bmi < 18.5) {
        return "偏瘦"
    } else if (bmi < 24.0) {
        return "正常"
    } else if (bmi < 28.0) {
        return "偏胖"
    } else {
        return "肥胖"
    }
}

// 计算圆面积
func 计算圆面积(半径: Float64): Float64 {
    return 3.14159 * 半径 * 半径
}

// 计算圆周长
func 计算圆周长(半径: Float64): Float64 {
    return 2.0 * 3.14159 * 半径
}

// 求两个数的最大值
func 求最大值(甲: Int64, 乙: Int64): Int64 {
    if (甲 > 乙) {
        return 甲
    } else {
        return 乙
    }
}

// 求三个数的最大值
func 求最大值(甲: Int64, 乙: Int64, 丙: Int64): Int64 {
    let 最大 = 求最大值(甲, 乙)
    return 求最大值(最大, 丙)
}

// 求两个数的最小值
func 求最小值(甲: Int64, 乙: Int64): Int64 {
    if (甲 < 乙) {
        return 甲
    } else {
        return 乙
    }
}

// 求三个数的最小值
func 求最小值(甲: Int64, 乙: Int64, 丙: Int64): Int64 {
    let 最小 = 求最小值(甲, 乙)
    return 求最小值(最小, 丙)
}

// 生成随机数
func 生成随机数(最小值: Int64, 最大值: Int64): Int64 {
    // 简化实现,实际应该使用随机数库
    return (最小值 + 最大值) / 2
}

3.2 进阶练习:字符串处理工具

// 字符串处理工具

main() {
    println("=== 字符串处理工具 ===")
    println("")
    
    let 文字: String = "Hello World"
    
    println("原字符串:${文字}")
    println("长度:${字符串长度(文字)}")
    println("转大写:${转大写(文字)}")
    println("转小写:${转小写(文字)}")
    println("反转:${反转字符串(文字)}")
    println("前5个字符:${截取字符串(文字, 0, 5)}")
    
    println("")
    
    let 姓名: String = "张三"
    println("是否为空:${是否为空(姓名)}")
    println("是否包含'张':${是否包含(姓名, "张")}")
}

// 获取字符串长度
func 字符串长度(文字: String): Int64 {
    return 文字.size
}

// 转大写
func 转大写(文字: String): String {
    // 简化实现
    return 文字
}

// 转小写
func 转小写(文字: String): String {
    // 简化实现
    return 文字
}

// 反转字符串
func 反转字符串(文字: String): String {
    var 结果: String = ""
    for (i in (文字.size - 1)..(-1)) {
        结果 = 结果 + 文字[i]
    }
    return 结果
}

// 截取字符串
func 截取字符串(文字: String, 开始: Int64, 长度: Int64): String {
    // 简化实现
    return 文字
}

// 判断是否为空
func 是否为空(文字: String): Bool {
    return 文字.size == 0
}

// 判断是否包含子串
func 是否包含(文字: String, 子串: String): Bool {
    // 简化实现
    return true
}

3.3 挑战练习:日期处理工具

// 日期处理工具

main() {
    println("=== 日期处理工具 ===")
    println("")
    
    // 假设今天是2024年6月15日
    let 年: Int64 = 2024
    let 月: Int64 = 6
    let 日: Int64 = 15
    
    println("日期:${年}年${月}月${日}日")
    println("星期:${获取星期几(年, 月, 日)}")
    println("是闰年:${是否闰年(年)}")
    println("本月天数:${获取月份天数(年, 月)}")
}

// 获取星期几(简化版)
func 获取星期几(年: Int64, 月: Int64, 日: Int64): String {
    let 星期列表 = ["日", "一", "二", "三", "四", "五", "六"]
    // 简化计算,假设2024年6月15日是星期六
    return "星期" + 星期列表[6]
}

// 判断是否闰年
func 是否闰年(年: Int64): Bool {
    return (年 % 4 == 0 && 年 % 100 != 0) || (年 % 400 == 0)
}

// 获取月份天数
func 获取月份天数(年: Int64, 月: Int64): Int64 {
    if (月 == 2) {
        if (是否闰年(年)) {
            return 29
        } else {
            return 28
        }
    } else if (月 == 4 || 月 == 6 || 月 == 9 || 月 == 11) {
        return 30
    } else {
        return 31
    }
}

// 计算年龄
func 计算年龄(出生年: Int64, 出生月: Int64, 出生日: Int64, 
             当前年: Int64, 当前月: Int64, 当前日: Int64): Int64 {
    var 年龄: Int64 = 当前年 - 出生年
    if (当前月 < 出生月 || (当前月 == 出生月 && 当前日 < 出生日)) {
        年龄 = 年龄 - 1
    }
    return 年龄
}

四、知识总结

4.1 核心概念回顾

  1. 方法:封装可重复使用的代码
  2. 定义方法func 名字(参数): 返回类型 { ... }
  3. 调用方法名字(参数)
  4. 参数:输入数据
  5. 返回值:输出结果

4.2 关于语法设计的总结

仓颉的方法定义语法:

func 计算BMI(体重: Float64, 身高: Float64): Float64 {
    return 体重 / (身高 * 身高)
}

优点:

  • func关键字直观
  • 方法名可以用中文
  • 与国际主流语言类似

可以改进的地方:

  • 参数类型后置
  • 返回类型后置

如果改进成类型前置:

// 设想中的改进
Float64 计算BMI(Float64 体重, Float64 身高) {
    return 体重 / (身高 * 身高)
}

希望华为能在未来版本中考虑这种更符合中国人习惯的语法!

4.3 关键代码速查

// 定义方法
func 方法名(参数: 类型): 返回类型 {
    return 结果
}

// 无返回值
func 方法名(参数: 类型): Unit {
    // 代码
}

// 无参数
func 方法名(): 返回类型 {
    return 结果
}

// 调用方法
let 结果 = 方法名(参数)

4.4 常见错误提醒

错误现象 原因 解决方法
方法未定义 调用在定义之前 把定义放在调用之前
参数类型错误 传入错误类型 检查参数类型
没有返回值 忘记写return 添加return语句
返回值类型错误 return的类型不对 检查返回类型

五、课后作业

5.1 巩固练习(必做)

练习1:计算器功能库

封装以下计算功能:

  • 加法、减法、乘法、除法
  • 取余数
  • 求平方
  • 开平方根

练习2:成绩处理功能

封装以下功能:

  • 计算平均分
  • 计算最高分
  • 计算最低分
  • 计算及格率
  • 判断等级

练习3:密码强度检测

封装功能检测密码强度。

5.2 创意编程(选做)

创意1:单位转换器

封装各种单位转换功能。

创意2:密码生成器

生成随机密码。

创意3:文本格式化工具

封装文本处理功能。

5.3 下篇预习

下一篇,我们将学习类和对象——面向对象编程


恭喜你完成了第7篇的学习! 🎉

现在你已经掌握了方法封装,可以创建可复用的代码了!

下节课,我们将学习面向对象编程,这是一个更强大的编程范式!

Logo

一站式 AI 云服务平台

更多推荐