《Flutter 从入门到实战:函数、类构造与继承核心语法手把手教学》
这篇文章系统介绍了Dart语言中的函数和类相关知识。主要内容包括: 函数部分: 函数定义方式(无参无返回值、有参有返回值) 函数的参数类型(必传参数、可选参数) 函数对象(回调函数)的使用 匿名函数和箭头函数的写法 类部分: 类的基础定义(属性、方法) 构造函数的主次之分(同名和命名构造函数) 类的继承和重写(extends和@override) 混入(mixin)和with关键字实现方法复用 文
函数
函数的定义
- 定义函数:无参数无返回值函数
- 定义函数:有参数有返回值函数
- 函数的特点:返回值类型和参数类型是可以省略的,但是不推荐
void main() {
print('计算的结果是:${add(1, 2)}');
test();
}
// 前端鸿蒙 全局函数 function test () {}
// 前端鸿蒙 const add = () => {}
// flutter定义函数 省略返回类型 类型(void/其他类型) 函数名() {}
// 前面的类型是返回类型
int add(int a, int b) {
return a + b;
}
// 没有返回类型的函数
void test() {
print("执行test函数");
}
test1() {}
void main() {
print(printHello); //无参数无返回值
print(sum(10, 20)); //有参数有返回值
}
// 1. 定义函数:无参数无返回值函数
void printHello() {
print('hello world');
}
// 2. 定义函数:有参数有返回值函数
// 需求:定义函数,计算任意两个整数的和,并返回计算结果
int sum(int a, int b) {
return a + b;
}
// 3. 函数的特点:
// ● 函数都有返回值,如果没有明确的指定返回值,那么默认返回null
// ● 返回值类型和参数类型是可以省略的

函数的参数(必传、可选)
函数的参数可以分为:必传参数、可选参数 (位置参数、 命名参数)
注意点 : 必传参数不能为空,可选参数可以为空,且参数可以设置默认值
可选参数
按位置传递:传参位置必须一 一对应上,可选参数需要用 [ ] 包裹起来, 在所有可选参数的 类型后面都加?
按命名传递:用 { }把可选参数都包裹起来,传参时不区分位置,因为会按照参数名查找 传递对应值的。
void main() {
// 函数的参数分必选参数和可选参数
slice(1, null);
getUserInfo(1, address: '北京昌平', age: 30, name: "大婶", sex: "男"); // 写法low到爆!!!
testFunc(1, city: '广州', location: '天河');
}
// int? end的含义是 end的值可以为null,但是空必须得传 不传报错
slice(int start, int? end) {
print('起始位置:$start, 结束位置:$end');
}
// 可选参数在声明的时候 要用 {} 把可选参数包裹起来
// 所有可选参数都加?
getUserInfo(int id,{String? name, int? age, String? sex,bool?isMarry = false, String? address}) {
print('姓名:$name, 年龄:$age, 性别:$sex, 婚姻状态:$isMarry, 地址: $address');
}
testFunc(int id, {String location = '北京顺义', String city = "深圳"}) {
print("当前的id:$id, 城市:$city, 位置: $location");
}
void main() {
printInfo('李华', 20);
}
// 函数的参数可以分为:必传参数、可选 位置参数、可选 命名参数
// 注意点:必传参数不能为空,可选参数可以为空,且参数可以设置默认值
// 1. 必传参数
void printInfo(String name, int age) {
print('姓名:$name, 年龄:$age');
}
// 2. 可选 位置参数 (传参位置必须一一对应上,可选参数需要用[]包裹起来)
void slice(String name, [int? age = 18]) {
print('姓名:$name, 年龄:$age');
}
// 3. 可选 命名参数 (命名参数需要用{}包裹起来,传参时不区分位置,是按照参数名查找传递对应值的)
void slice2(String name, {int? age = 18, String? hobby = '吃饭'}) {
print('姓名:$name, 年龄:$age');
}


void main() {
// 函数的参数分必选参数和可选参数
slice(1, null);
getUserInfo(1, address: '北京昌平', age: 30, name: "大婶", sex: "男"); // 写法low到爆!!!
testFunc(1, city: '广州', location: '天河');
}
// int? end的含义是 end的值可以为null,但是空必须得传 不传报错
slice(int start, int? end) {
print('起始位置:$start, 结束位置:$end');
}
// 可选参数在声明的时候 要用{}把可选参数包裹起来
// 所有可选参数都加?
getUserInfo(int id,
{String? name,
int? age,
String? sex,
bool? isMarry = false,
String? address}) {
print('姓名:$name, 年龄:$age, 性别:$sex, 婚姻状态:$isMarry, 地址: $address');
}
testFunc(int id, {String location = '北京顺义', String city = "深圳"}) {
print("当前的id:$id, 城市:$city, 位置: $location");
}
函数对象(回调函数)
callback
把函数当成属性传递给使用方,
调用就是-方法名()
函数可以作为对象赋值给其他变量, 函数可以作为参数传递给其他函数
void main() {
// 匿名函数
start((int a) {
print("调用了函数:$a");
});
}
// 声明一个函数
// callback: () => void
start(Function callback) {
// capturer.on("readData", (bf) => )
callback(1); // 谁写小括号谁是调用
}
import 'dart:ffi';
void main() {
func(() => {print('执行了')});
}
// 1. 函数可以作为对象赋值给其他变量
void func(Function demo) {
demo();
}
// 2. 函数可以作为参数传递给其他函数
void Func2( Void Function(String str, int age) demo ) {
demo('hello world', 18);
}

匿名函数
匿名函数:没有名称的函数
声明匿名函数:通过变量接受一个没有名称的函数
var 变量 = 函数 var fun = ( )=>{ }
把匿名函数作为参数传递给其他函数
声明函数,接受匿名函数当参数
void callback( Function 匿名函数 ) { 匿名函数(参数1:值,参数2:值 ) }
调用函数,传递匿名函数当参数
callback( () {
print('回调函数执行le');
} );
void main() {
// 1.匿名函数赋值给变量,并调用 (调用匿名函数并传值)
print( func(1, 2) );
// 2.可以作为参数传递给其他函数去调用(回调函数)
callback( () {
print('回调函数执行le');
}
);
}
// 1.匿名函数
var func = (int a, int b) {
return a + b;
};
// 接受的参数是一个匿名函数
void callback( Function func ) {
func(1, 2);
}
箭头函数
Flutter中的箭头函数:只有当代码只有一行时能简写为箭头函数,其他情况都不允许!!和鸿蒙不同
void main() {
int ret1 = sum1(10, 20);
print(ret1);
int ret2 = sum2(30, 40);
print(ret2);
}
// 思考:以下代码可以简写吗?
sum1(a, b) {
return a + b; // 函数体只有一行代码
}
// 箭头函数简写函数体:简写只有一行代码的函数体
sum2(a, b) => a + b;
类
类的基础定义
main() {
// Person p = new Person(); // 接收创建的新对象
Person p = Person(); // Dart 可省略 new 关键字
print(p.name); // 访问属性
p.sayHello(); // 调用方法
}
// 类的基础用法
class Person {
// 属性(相当于定义变量)
String name = '张三';
int age = 18;
String sex = '男';
// 方法(相当于定义函数)
void sayHello() {
print('我是$name,今年$age,我是$sex');
}
}
// 需求:定义Person类,属性: 名字和年龄,方法:吃饭
void main() {
// Person man = new Person();
//flutter中,使用类创建对象时可省略 new 关键字
Person man2 = Person();
print(man2.name); //张三
Person woman = new Person();
woman.age = 18;
print(man2.age); //18
}
class Person {
// 属性
String name = '张三';
int age = 18;
// 方法
void eat() {
print('${this.name}正在吃饭');
}
}

类的构造函数
同名构造函数(主)
同名构造函数 也被称为主构造函数,与类名一致
注意:与类同名的构造函数只能有一个
main() {
// 调用主构造函数
Person p = new Person(name: '张三', age: 18, sex: '男');
p.sayHello(); // 调用方法
}
// 类的基础用法
class Person {
String? name;
int? age;
String? sex;
// 构造函数(主),跟类名同名
Person({String? name, int? age, String? sex}) {
print('主构造函数被调用了');
this.name = name;
this.age = age;
this.sex = sex;
}
void sayHello() {
print('你好,我是$name,我今年$age岁,我是$sex');
}
}
// 需求:定义Person类,属性:名字和年龄,方法:吃饭
void main() {
// 调用主构造函数
Person man = Person('张三', 18, '男'); //必填
man.intro();
Person woman = Person('小红', 15, '女'); //必填
woman.intro();
}
class Person {
// 属性
String? name;
int? age;
String? gender;
// 主构造函数, (和类名同名) 也被称为默认构造函数
// Person({String? name, int? age, String? gender}) {//可选参数,填写时注意对应参数位置
Person(String name, int age, String gender) {
//必填参数 必须填写
// print('这是主构造函数');
this.name = name;
this.age = age;
this.gender = gender;
}
// 方法
intro() {
print('我的名字是$name,年龄是: $age,性别是: $gender');
}
}

命名构造函数(次)
命名构造函数(也称为次构造函数)类中可以有多个次构造函数
类名.方法(参数...) 然后返回一个实例化对象,
main() {
// 调用主构造函数
Person p = new Person(name: '张三', age: 18, sex: '男');
p.sayHello(); // 调用方法
// 调用命名构造函数
Person p1 = new Person.male(name: '李四', age: 19);
p1.sayHello();
}
// 类的基础用法
class Person {
// 属性(相当于定义变量)
String? name;
int? age;
String? sex;
// 构造函数(主),跟类名同名
Person({String? name, int? age, String? sex}) {
print('主构造函数被调用了');
this.name = name;
this.age = age;
this.sex = sex;
}
// 命名构造函数(次),可以有多个
Person.male({String? name, int? age}) {
print('命名构造函数被调用了');
this.name = name;
this.age = age;
this.sex = '男';
}
// 方法(相当于定义函数)
void sayHello() {
print('你好,我是$name,我今年$age岁,我是$sex');
}
}
简写:主+次 构造函数
// 需求:定义Person类,属性:名字和年龄,方法:吃饭
void main() {
// 1. 同名构造函数创建对象
Person man = Person('张三', 18, '男');
man.intro();
// 2. 命名构造函数创建对象
Person one = Person.init('次构造1', 18);
Person two = Person.init2('次构造2');
one.intro();
two.intro();
}
class Person {
// 属性
String? name;
int? age;
String? gender;
// 同名构造函数 (主, 构造函数和类名同名)
// Person(String name, int age, String gender) {
// // print('这是主构造函数');
// this.name = name;
// this.age = age;
// this.gender = gender;
// }
//同名构造函数(主) 简写
Person(this.name, this.age, this.gender);
// 命名构造函数(次, 为了创建对象的方式更加灵活,可以存在多个次构造函数)
// Person.init(String name, int age) {
// // print('这是命名构造函数');
// this.name = name;
// this.age = age;
// this.gender = '女';
// }
// 命名构造函数(次) 简写
Person.init(this.name, this.age) : this.gender = '女';
// Person.init2(String name) {
// // print('这是命名构造函数');
// this.name = name;
// this.age = 28;
// this.gender = '女';
// }
// 命名构造函数(次) 简写
Person.init2(this.name)
: this.age = 28, this.gender = '女';
// 方法
intro() {
print('我的名字是$name,年龄是$age,性别是$gender');
}
}

类的私有属性和方法
flutter中没有public和private
flutter中的属性和方法只要加上下划线,就是私有属性
// 钱包类
// 鸿蒙中类,需要导出才能给外部提供使用M,flutter中不需要导出
class Wallet {
// 私有属性(属性前面加下划线)
double _money = 0;
// 私有方法(方法前面加下划线)
_moneyIntro() {
print('这是钱包的钱, 可以买东西');
}
// 保存钱
SaveMoney(money) {
print('保存钱 ${_money += money}');
}
// 取钱
getMoney(money) {
print('取钱 ${_money -= money}');
}
// 显示余额
showMoney() {
_moneyIntro();
print('余额为:$_money');
}
}
import 'lib/MoneyBao.dart';
void main() {
// 类比鸿蒙 const 对象:类型 = new 类();
// Flutter 类型 对象 = new 类();
var wallet = new Wallet();
// wallet = new Wallet();
wallet.SaveMoney(1000);
wallet.getMoney(200);
wallet.showMoney();
}

继承
前端鸿蒙
implements - 实现并继承-需要我们自己去实现
extends - 直接继承,不写东西是可以的
Flutter
简单继承父类, 通过extends继承
重写父类的方法 通过@override 修饰 需要重写的父类的方法,在方法名中修改重写
extends继承父类
void main() {
Person person = Person('张三', 18);
person.sayHello();
print('=================');
Teacher teacher = Teacher('李四', 28, '语文');
teacher.saySubject();
}
// 定一个父类
class Person {
// 定义属性
String name;
int age;
// 定义构造函数
Person(this.name, this.age);
// 定义方法
void sayHello() {
print('你好,我是$name, 我今年$age岁');
}
}
// 定义一个老师类继承自父类
class Teacher extends Person {
// 定义学科属性
// late String subject;
String subject;
// 继承父类的属性
// String name;
// int age;
// 继承父类的构造函数, 这种方式 了解即可
// 需要在自己的属性前面要加 late 代表延迟初始化 一定会有值,晚一会而已 (和鸿蒙有点不太一样)
// Teacher(String name, int age, String subject) : super(name, age) {
// this.subject = subject;
// }
// 构造函数 常用的方式
Teacher(super.name, super.age, this.subject);
// 定义方法
void saySubject() {
print('我是$name老师, 年龄: $age, 我教的学科是$subject');
}
}

extends并重写方法 @override
@override重写(覆盖)从父类继承的方法,或者实现接口中定义的方法
这两种情况都需要用 @override 来显式标记。
main() {
// 1. 实例化父类
Person p1 = Person();
p1.sayHello();
// 2. 实例化子类
Student s1 = Student();
s1.name = '张三';
s1.age = 18;
s1.sayHello();
s1.sayId();
// 3. 实例化子类
Teacher t1 = Teacher();
t1.name = '李四';
t1.age = 33;
t1.subject = 'Flutter';
t1.sayHello();
t1.saySubject();
}
// 定一个父类
class Person {
// 定义属性
String name = '人类';
int age = 0;
// 定义方法
void sayHello() {
print('你好,我是$name,我今年$age岁');
}
}
// 定义子类 - 学生类
class Student extends Person {
// 定义 id 属性
int id = 1;
// 定义方法
void sayId() {
print('我是学生,我的学号是$id');
}
// 重写父类的方法
@override
void sayHello() {
print('我是学生,我重写了父类的方法,我是$name,我今年$age岁,我的学号是$id');
}
}
// 定义子类 - 老师类
class Teacher extends Person {
// 定义学科属性
String subject = '鸿蒙';
// 定义方法
void saySubject() {
print('我是老师,我教的学科是$subject');
}
// 重写父类的方法
@override
void sayHello() {
print('我是老师,我重写了父类的方法,我是$name,我今年$age岁,我教的学科是$subject');
}
}


import '06_类的继承.dart';
void main() {
// 父类
One o = One(name: '张安');
o.eat();
// 子类
Two two = Two(name: '小趴菜');
two.eat();
}
// 父类
class One {
String? name;
int? age;
double? height;
String? hobby;
double? weight;
// 同名构造函数
One({this.age, this.name, this.height, this.hobby});
// 方法
eat() {
print('$name 在吃饭');
}
sleep() {
print('$name 喜欢睡觉');
}
jieShao() {
print('$name今年$age 岁了 身高$height');
}
}
// 子类 继承父类
class Two extends One {
// 继承父类构造函数
// 两步:
// 第一步 接收父类 传递过来的参数
// 第二步 调用父类的构造函数 把值传递过去, super 当前的父类构造函数对象
Two({
String? name,
int? age,
double? height,
String? hobby,
double? weight,
}) : super(name: name, age: age, height: height, hobby: hobby);
// 重写父类的方法
@override
eat() {
// TODO: implement eat
// return super.eat();//继承父类的方法, 输出打印的还是父类的
// 重写父类的方法
print('$name 喜欢吃饭');
}
}
super 关键字(父类)
可以使用 super() 调用父类的构造函数
main() {
// 1. 实例化子类
Student s1 = Student('张三', 18, 10086);
s1.sayId();
// 2. 实例化子类
Teacher t1 = Teacher('李四', 38, '数学');
t1.saySubject();
}
// 定一个父类
class Person {
// 定义属性
String name;
int age;
// 定义构造函数
Person(this.name, this.age);
// 定义方法
void sayHello() {
print('你好,我是$name,我今年$age岁');
}
}
// 定义子类 - 学生类
class Student extends Person {
// 定义 id 属性
late int id;
// 定义构造函数
Student(super.name, super.age, this.id);
// 非简写(了解),可以使用 super() 调用父类的构造函数
// Student(String name, int age, int id) : super(name, age) {
// this.id = id;
// }
// 定义方法
void sayId() {
// 可通过 super 调用父类的方法
super.sayHello();
print('我是学生,我的学号是$id');
}
}
// 定义子类 - 老师类
class Teacher extends Person {
// 定义学科属性
String subject;
// 定义构造函数
Teacher(super.name, super.age, this.subject);
// 定义方法
void saySubject() {
// 可通过 super 调用父类的方法
super.sayHello();
print('我是老师,我教的学科是$subject');
}
}
可选命名参数 和 required必填

main() {
// 1. 实例化父类,没有传 age 使用默认值
Person p1 = new Person(name: '张三');
p1.sayHello();
// 2. 实例化子类
Student s1 = new Student(name: '张四', age: 18, id: 10086);
s1.sayId();
// 3. 实例化子类
Teacher t1 = new Teacher(name: '李四', age: 38, subject: '数学');
t1.saySubject();
}
// 定一个父类
class Person {
// 定义属性
String name; // 必传参数
int? age; // 可选参数
// 定义构造函数,升级成可选命名参数,必传参数需要添加 required 关键字
Person({required this.name, this.age = 18});
// 定义方法
void sayHello() {
print('你好,我是$name,我今年$age岁');
}
}
// 定义子类 - 学生类
class Student extends Person {
// 定义 id 属性
int id;
// 定义构造函数,升级成可选命名参数
Student({required super.name, super.age, required this.id});
// 非简写(了解),可以使用 super() 调用父类的构造函数
// Student(String name, int age, int id) : super(name, age) {
// this.id = id;
// }
// 定义方法
void sayId() {
// 可通过 super 调用父类的方法
super.sayHello();
print('我是学生,我的学号是$id');
}
}
// 定义子类 - 老师类
class Teacher extends Person {
// 定义学科属性
String subject;
// 定义构造函数,升级成可选命名参数
Teacher({required super.name, super.age, required this.subject});
// 定义方法
void saySubject() {
// 可通过 super 调用父类的方法
super.sayHello();
print('我是老师,我教的学科是$subject');
}
}
混入(mixin、with)
让子类有一些方法,但又不是全部共享的方法,不适合放父类中
可以用mixin 扩展方法,需要用到次方法的类用With使用

/*
[思考]:如何让子类Woman也有唱歌的方法?
[解决]:
方式1:将唱歌的方法,定义到子类Woman中(代码冗余)
方式2:将唱歌的方法,定义到父类Person中(代码扩展性不好,唱歌的方法不能被其他类复用)
方式3:使用mixin扩展一个类,扩展类中定义唱歌的方法
[mixin] 表示一个没有构造函数的类,这个类的方法可以组合到其他类中实现代码复用
[mixin] 可以同时对某个类设置多个扩展类,也可以扩展属性
*/
void main() {
// 创建男人对象
Man man = Man('李雷', 13);
print(man.name);
man.eat();
man.sing(man.name!);
print('---------------------------------------');
// 创建女人对象
Woman woman = Woman('韩梅梅', 14);
print(woman.name);
woman.eat();
woman.sing(woman.name!);
woman.dancing(woman.name!);
}
/// 人类
class Person {
Person(this.name, this.age);
String? name;
int? age;
void eat() {
print('$name -- eat');
}
}
/// 男人类
class Man extends Person with SingMinxin {
// 定义子类构造函数
Man(super.name, super.age);
}
/// 女人类
class Woman extends Person with SingMinxin, DancingMinxin {
// 定义子类构造函数
Woman(super.name, super.age);
}
// -----------mixin扩展类一mixin扩展类--------------
// 唱歌的方法
mixin SingMinxin {
void sing(String name) {
print('$name -- 爱唱歌');
}
}
// 跳舞的方法
mixin DancingMinxin {
void dancing(String name) {
print('$name -- 爱跳舞');
}
}
更多推荐

所有评论(0)