30天计划第1天-环境搭建 + Dart 基础语法

-
-
2025-09-30 11:32
  • 学习内容

  1. 安装 Flutter SDK(Windows/macOS 按官方教程)

  2. 配置 Android Studio(安装 Flutter 插件、模拟器)

  3. Dart 基础:变量(var/int/String)、数据类型(List/Map)

  • 实践任务

    1. 成功运行 Flutter 自带的「计数器 Demo」

    2. 用 DartPad 写 3 个小例子:定义变量、创建 List/Map、打印数据

一、安装Flutter SDK

1.  环境变量配置及下载Flutter SDK

Flutter官网:https://flutter.dev/docs/get-started/install/windows

(*建议)Flutter中国官网:https://docs.flutter.cn/community/china/

Flutter镜像站点:China Flutter User Group (CFUG) 维护着一个 Flutter 简体中文网站 https://flutter.cn 以及镜像。

本文就依据官方教程,使用CFUC镜像。

1.1 打开powershell

下面小节中,前面的C:>是当前执行命令的位置, 在后面步骤中需要注意位置关系,输命令的时候不要带进去了。

1.2 将 PUB_HOSTED_URL 设置为镜像站点。

C:> $env:PUB_HOSTED_URL="https://pub.flutter-io.cn"

验证是否设置成功:

C:> echo $env:PUB_HOSTED_URL

若输出:

https://pub.flutter-io.cn

则设置成功。

1.3 将 FLUTTER_STORAGE_BASE_URL 设置为镜像站点。

C:> $env:FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn"

验证是否设置成功:

C:> echo $env:FLUTTER_STORAGE_BASE_URL

若输出:

https://storage.flutter-io.cn

则设置成功。

1.4 从镜像站点下载 Flutter 压缩包。在你常用的浏览器中访问并下载 Flutter SDK 压缩包

打开链接后,下滑,找到Stable channel章节(如下图),Stable channel是稳定版本列表。

点击版本号,即可开始下载。这里我选择当前最新版本,即:3.35.5。

包体有1.6G,但是因为设置了镜像,所以速度并不慢,等待下载即可…

1.5 创建一个可以安装 Flutter 的文件夹,然后将文件夹命名为 Flutter。

例如我的路径为:F:\\Flutter。

注意:文件夹路径中不要有中文、空格,防止后期编译时出现奇奇怪怪的报错。

1.6 将1.4下载的包拷贝到1.5创建的目录中,解压,并提取SDK。

解压时请选择解压到当前文件夹,最终效为:F:\\Flutter\flutter,如下图:

1.7 将Flutter添加到环境变量中

先切换到1.5创建的Flutter目录

C:> cd F:\\Flutter

执行:

F:\Flutter> $env:Path = "$pwd\flutter\bin;$env:Path"

1.8 运行 Flutter doctor 来验证安装。

 F:\Flutter> flutter doctor

它会检查你的开发环境,并提示缺少的组件。

也可以用:

F:\Flutter> flutter --version

若输出版本信息,则安装成功。

2. 永久系统变量

第一步过程中设置的环境变量均是临时环境变量,仅限当前会话有效,若要永久有效,请按照下面方法进行配置。

如果想每次打开 PowerShell 都自动用国内镜像,按以下步骤配置系统环境变量:
(1)按下 Win + R,输入 sysdm.cpl,打开「系统属性」面板;
(2)点击「高级」→「环境变量」;


(3)在「用户变量」或「系统变量」中,点击「新建」:
变量名:

PUB_HOSTED_URL

变量值:

https://pub.flutter-io.cn

(4)再新建一个变量(解决 Flutter 资源下载慢):
变量名:

FLUTTER_STORAGE_BASE_URL

变量值:

https://storage.flutter-io.cn

(5)点击「系统变量」→ [Path],点击新建,在最下面新加一条,输入flutter的bin目录的地址,如果按照前面的步骤,则输入:

F:\Flutter\flutter\bin

可以根据实际安装路径进行调整。

(6)点击「确定」保存。

3. 关于发布配置机器发布 package

官方教程中有“配置你的机器发布 package”这一步,这步的目的是将你开发的库共享到官方仓库,可以根据自己的需要去官方看配置教程,一般是用不到。

至此,Flutter SDK就安装完毕了!
 

二、配置其他开发工具

在cmd命令行中执行:

flutter doctor

根据输出结果,及自身需要,配置web开发环境、Android开发环境或者桌面开发环境。

三、Dart基础:变量、数据类型

1.  变量定义方式

Dart变量定义有三种方式:var、dynamic、具体类型(int, String等),核心区别是“是否限制数据类型”。

(1)最常用:var(自动推断类型,推荐优先用)

var 会根据你赋值的内容,自动判断变量类型,赋值后类型就固定了(不能再改类型),如:

void main() {
  // 1. 用 var 定义变量,赋值数字 10,Dart 自动推断为 int 类型
  var age = 10;
  print(age); // 输出:10
  print(age.runtimeType); // 查看类型,输出:int(整数类型)

  // 2. 错误示范:var 赋值后类型固定,不能再改其他类型
  // age = "10岁"; // 会报错:A value of type 'String' can't be assigned to a variable of type 'int'

  // 3. 先定义变量,后赋值(需保证后续赋值类型一致)
  var name; // 此时类型是 dynamic(动态类型)
  name = "小明"; // 赋值后类型变为 String
  print(name); // 输出:小明
  // name = 20; // 再改数字会报错:类型不匹配
}

var 简洁高效,能自动帮你 “约束类型”,避免低级错误,日常开发 80% 场景用它就够了。

(2)特殊场景:dynamic(完全动态类型,慎用)

dynamic 定义的变量,类型完全不固定,可以随时改类型 —— 灵活性高,但会失去 Dart 的 “类型安全” 保护(容易出隐藏 bug),除非特殊需求(比如处理不确定类型的数据),否则少用。

void main() {
  dynamic score = 95; // 初始是 int 类型
  print(score); // 输出:95

  score = "优秀"; // 改成 String 类型,不报错
  print(score); // 输出:优秀

  score = true; // 再改成 bool 类型,仍不报错
  print(score); // 输出:true
}

如果不是特别确定 “为什么要用 dynamic”,就别用,优先用 var。

(3)明确类型:具体类型声明(严谨场景用)

2. 数据类型

Dart是强类型语言。

数据类型分两大类:基本数据类型、复杂数据类型。

基本数据类型

(1)null

空值。

Dart 2.12+ 启用 空安全(Null Safety) 后,默认不允许变量为 null,需手动加 ? 表示 “可空”。

String? addr = null;

(2)num/int/double

num包含int和double,可自动适配。

// int转double
int a = 1;
double b = a.toDouble();

// double转int
double c = 3.9;
int d = c.toInt(); // 此时会输出3,double转int是直接舍弃小数点后的数字
int e = c.round(); // 

(3)String

类似Python,可以单引号也可以双引号。

String str1 = 'Hello';
String str2 = 'World!';

String str3 = str1 + str2; // 拼接字符串,得到: HelloWorld!

int age = 10;
String str4 = '年龄:' + age + '岁';
String str5 = '年龄:${age}岁'; // 模板字符串,效果和str4一致

// 高频用法
String str6 = "flutter";
print(str6.length); // 长度:6
print(str6.toUpperCase()); // 转大写:FLUTTER
print(str6.contains("utt")); // 是否包含“utt”:true

(4)bool

只有true或者false两个值,没有非0即真的说法:if (1) 是会报错的。

复杂数据类型

(1)List

类似于其他语言的数组,向量,是有序的,可以通过下标直接访问。

定义List

// 方式1:显式声明类型 + 初始化(推荐,类型安全)
List<String> names = ["小明", "小红", "小李"]; // 存储 String 类型的列表
List<int> scores = [95, 88, 92];           // 存储 int 类型的列表

// 方式2:用 var 自动推断类型(简洁)
var fruits = ["苹果", "香蕉", "橙子"]; // 自动推断为 List<String>
var ages = [20, 21, 19];            // 自动推断为 List<int>

// 方式3:创建空列表(后续添加数据)
List<String> emptyList1 = [];          // 空的 String 列表
List<int> emptyList2 = List.empty();   // 另一种创建空列表的方式(Dart 2.12+)

// 打印列表
print(names);   // 输出:[小明, 小红, 小李]
print(scores);  // 输出:[95, 88, 92]

增删改查

List<String> fruits = ["苹果", "香蕉"];

// 1. 查:获取元素(通过索引,从 0 开始)
print(fruits[0]); // 输出:苹果(第 1 个元素)
print(fruits[1]); // 输出:香蕉(第 2 个元素)
// print(fruits[2]); // 报错:索引越界(列表只有 2 个元素,索引最大为 1)

// 2. 增:添加元素
fruits.add("橙子");          // 末尾添加 1 个元素 → ["苹果", "香蕉", "橙子"]
fruits.addAll(["葡萄", "芒果"]); // 末尾添加多个元素 → ["苹果", "香蕉", "橙子", "葡萄", "芒果"]
print(fruits); // 输出:[苹果, 香蕉, 橙子, 葡萄, 芒果]

// 3. 改:修改元素(通过索引)
fruits[1] = "西瓜"; // 把索引 1 的元素改成“西瓜” → ["苹果", "西瓜", "橙子", "葡萄", "芒果"]
print(fruits);     // 输出:[苹果, 西瓜, 橙子, 葡萄, 芒果]

// 4. 删:删除元素
fruits.remove("橙子"); // 删除指定元素 → ["苹果", "西瓜", "葡萄", "芒果"]
fruits.removeAt(2);   // 删除索引 2 的元素 → ["苹果", "西瓜", "芒果"]
print(fruits);        // 输出:[苹果, 西瓜, 芒果]

// 5. 其他常用操作
print(fruits.length);       // 列表长度 → 3
print(fruits.contains("西瓜")); // 是否包含某个元素 → true
fruits.clear();             // 清空列表 → []
print(fruits);              // 输出:[]

遍历链表

List<String> names = ["小明", "小红", "小李"];

// 方式1:普通 for 循环(通过索引遍历)
for (int i = 0; i < names.length; i++) {
	print("第 ${i+1} 个学生:${names[i]}");
}
// 输出:
// 第 1 个学生:小明
// 第 2 个学生:小红
// 第 3 个学生:小李

// 方式2:forEach 方法(更简洁,推荐)
names.forEach((name) {
	print("学生:$name");
});
// 输出:
// 学生:小明
// 学生:小红
// 学生:小李

(2)Map

定义Map

// 方式1:显式声明类型(Key 类型, Value 类型)+ 初始化(推荐)
Map<String, dynamic> user = {
    "name": "小明",   // Key: "name"(String),Value: "小明"(String)
    "age": 20,       // Key: "age"(String),Value: 20(int)
    "isStudent": true // Key: "isStudent"(String),Value: true(bool)
};
// 说明:dynamic 表示 Value 可以是任意类型(String/int/bool 等)

// 方式2:用 var 自动推断类型(简洁)
var product = {
    "id": 1001,
    "name": "手机",
    "price": 2999.9
}; // 自动推断为 Map<String, dynamic>

// 方式3:创建空 Map(后续添加键值对)
Map<String, String> emptyMap1 = {};          // 空的 Map(Key 和 Value 都是 String)
Map<String, int> emptyMap2 = Map.empty();     // 另一种创建空 Map 的方式

// 打印 Map
print(user);    // 输出:{name: 小明, age: 20, isStudent: true}
print(product); // 输出:{id: 1001, name: 手机, price: 2999.9}

增删改查

Map<String, dynamic> user = {
    "name": "小明",
    "age": 20
};

// 1. 查:通过 Key 获取 Value
print(user["name"]); // 输出:小明
print(user["age"]);  // 输出:20
print(user["gender"]); // 输出:null(Key 不存在时返回 null)

// 2. 增:添加键值对(Key 不存在则新增)
user["gender"] = "男";    // 新增 Key: "gender",Value: "男"
user["address"] = "北京"; // 新增 Key: "address",Value: "北京"
print(user); // 输出:{name: 小明, age: 20, gender: 男, address: 北京}

// 3. 改:修改 Value(Key 已存在则覆盖)
user["age"] = 21; // Key "age" 已存在,修改 Value 为 21
print(user);      // 输出:{name: 小明, age: 21, gender: 男, address: 北京}

// 4. 删:删除键值对
user.remove("address"); // 通过 Key 删除
print(user);            // 输出:{name: 小明, age: 21, gender: 男}

// 5. 其他常用操作
print(user.length);       // Map 中键值对的数量 → 3
print(user.containsKey("name")); // 是否包含某个 Key → true
print(user.values);       // 获取所有 Value → (小明, 21, 男)
print(user.keys);         // 获取所有 Key → (name, age, gender)
user.clear();             // 清空 Map → {}
print(user);              // 输出:{}

遍历

Map<String, dynamic> user = {
    "name": "小明",
    "age": 20,
    "isStudent": true
};


// forEach 遍历:参数是 (Key, Value)
user.forEach((key, value) {
   print("$key: $value");
});
// 输出:
// name: 小明
// age: 20
// isStudent: true

四、使用AndroidStudio运行Flutter自带Demo:计数器

AndroidStudio版本:2025.1.4

1. 安装Flutter插件

2. 新建Flutter工程

(1)选择File→New→New Flutter Project→设置SDK路径→设置工程信息

(2)Android language可以选择Java或者Koltin,不同选择后面配置可能有少许差异。这里选择Koltin。

3. 选择调试平台

Flutter支持多平台,因此这里可以根据需要选择目标平台。

桌面版和Web版

选择平台后直接点绿色箭头运行,等待即可。

安卓版

安卓需要先启动虚拟机或者连接真机后,这里才能选择安卓设备,选完直接点运行即可。

需要注意,由于网络原因,最好修改下镜像,否则很容易失败。

我这里用的是Android10版本的API,修改如下:

(1)修改Root级的build.gradle文件

点击左侧项目树→android→build.gradle.kts(因为前面选择了Koltin语言,所以这里是kts文件),将allprojects里面的repositories进行如下修改:

allprojects {
    repositories {
        // 1. 优先添加 AndroidX 专用国内镜像(同步最快)
        maven { url = uri("https://mirrors.huaweicloud.com/repository/android") } // 华为云 Android 专用
        maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public/") } // 腾讯云
        maven { url = uri("https://maven.aliyun.com/repository/google") } // 保留阿里云 Google 源
        maven { url = uri("https://maven.aliyun.com/repository/jcenter") } // 保留阿里云 JCenter
        maven { url = uri("https://maven.aliyun.com/nexus/content/groups/public") } // 保留阿里云公库
        maven { url = uri("https://jitpack.io") } // 保留 jitpack(第三方库可能需要)

        // 2. 最后添加默认源(防止国内源遗漏时兜底,实际不会优先走)
        google()
        mavenCentral()
    }
}

其余配置不变。

(2)修改app级别的build.gridle文件

点击左侧项目树→android→app→build.gradle.kts,在android块中加入下列信息:

// 新增:添加国内镜像仓库(优先下载 AndroidX 依赖)
repositories {
    maven { url = uri("https://mirrors.huaweicloud.com/repository/android") } // 华为云 Android 专用
    maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public/") } // 腾讯云
    maven { url = uri("https://maven.aliyun.com/repository/google") } // 阿里云 Google 源
    maven { url = uri("https://jitpack.io") } // 第三方库兜底
    google() // 默认源兜底(实际会优先走国内镜像)
    mavenCentral()
}
(3)在AS终端中执行:
flutter clean # 清除缓存
flutter pub get # 更新项目依赖包
flutter run # 运行项目(可选)

可以通过命令行运行项目,也可以点击绿色箭头运行项目。


目录