使用网页进行语法调试:网页编程适用于语法基础
this 是一个关键字,用于引用当前实例或对象。它通常用于区分实例变量和局部变量,特别是在类的方法中,当方法参数和实例变量具有相同的名称时。
使用举例:
class Person {
String name;
Person(this.name); // 构造函数
void printName() {
print(this.name); // 使用this引用实例变量
}
}
void main() {
Person person = Person('John');
person.printName();
}
使用类型推到创建不同类型的属性
var name = 'fenghanxu';
var age = '2023';
var list = ['1','2'];
var json = {
'key':'name',
'value':'fenghanxu'
};
print(name);
print(age);
print(list);
print(json['key']);
final 是一个关键字,用于声明一个只能被赋值一次的变量。一旦被赋值,final 变量的值就不能再被修改。final 变量可以在声明时初始化,也可以在构造函数中初始化。
final name = 'fenghanxu';
final age = '2023';
final list = ['1','2'];
final json = {
'key':'name',
'value':'fenghanxu'
};
print(name);
print(age);
print(list);
print(json['key']);
const name = 'fenghanxu';
const age = '2023';
const list = ['1','2'];
const json = {
'key':'name',
'value':'fenghanxu'
};
print(name);
print(age);
print(list);
print(json['key']);
if (a < b){
print('yes');
};
var list = ['1','2','3'];
for (final obj in list) {
print(obj);
}
for (int index = 0; index < list.length; index++) {
print(list[index]);
}
var year = 2014;
while (year < 2016) {
year += 1;
print(year);
}
var list = [1,2,3,4,5,6,7,8,9];
for (final obj in list) {
if (obj == 4) {
continue;
}
print(obj);
}
var list = [1,2,3,4,5,6,7,8,9];
for (final obj in list) {
if (obj >= 4) {
break;
}
print(obj);
}
var fruit = 'apple';
switch (fruit) {
case 'apple':
print('yes');
break;
case 'orange':
print('no');
break;
case 'banana':
print('no');
break;
default:
print('default');
}
assert 是一种用于在开发过程中验证布尔表达式的工具。它通常用于检查代码中的不变量或确保代码中的条件得到满足。在生产环境中,默认情况下,assert 语句会被忽略,不会执行。只有在开发模式下(使用 dart --enable-asserts 运行应用程序)才会执行 assert 语句。
assert(boolean_expression, optional_message);
boolean_expression
是一个布尔表达式,如果该表达式为 false,则会引发一个异常。
optional_message
是一个可选的消息,用于描述断言失败的原因
举例:
int x = 5;
int y = 10;
// 使用 assert 检查条件
assert(x < y, "x should be less than y");
// assert 语句可以没有消息
assert(x > 0);
// 下面这个断言将会失败,并显示指定的消息
assert(x > y, "This assertion will fail");
print("Code after assertions");
简写语法用于仅包含一条语句的函数。该语法在将匿名函数作为参数传递时非常有用:
普通写法
·
void isNoble_0(int number) {
print(number);
}
//调用
isNoble_0(3);
胖箭头写法
void isNoble_1(int number) => print(number);
//调用
isNoble_1(4);
class Spacecraft {
String name;
DateTime? launchDate;
// 只读非最终属性
int? get launchYear => launchDate?.year;
// 构造函数,带有用于分配给成员的语法糖。
Spacecraft(this.name, this.launchDate) {
// Initialization code goes here.
}
// 转发到默认构造函数的命名构造函数。
Spacecraft.unlaunched(String name) : this(name, null);
// 实例方法.
void describe() {
print('Spacecraft: $name');
var launchDate = this.launchDate;
if (launchDate != null) {
int years = DateTime.now().difference(launchDate).inDays ~/ 365;
print('Launched: $launchYear ($years years ago)');
} else {
print('Unlaunched');
}
}
}
问题1:
Spacecraft.unlaunched(String name) : this(name, null);
上面的写法其实跟下面的写法是一样
Spacecraft.unlaunched(String name) : this(name, null);其实这句话的意思就是把方法参数那么传进来的值赋值给类里面的属性name
Spacecraft.unlaunched(String name) {
// 构造函数体内的代码
this.name = name;
this.launchDate = null;
}
问题2:这两个属性的创建有什么区别
最大的区别就是 ?
带问号就是属性允许接收一个null,没有问号不能接收
String name;
DateTime? launchDate;
var a = 1;
print(a.runtimeType);
print(Queue.initialCapacity);
print(Queue.sendMessage())
class Queue {
//静态属性
static const initialCapacity = 16;
//静态方法
static String sendMessage() {
return 'fenghanxu';
}
}
class Point {
double? x; // Declare instance variable x, initially null.
double? y; // Declare y, initially null.
double z = 0; // Declare z, initially 0.
}
class Point {
void sendPoint(int x, int y) {
print('${x},${y}');
}
}
// 定义一个简单的类
class Person {
// 类的属性
String name;
int age;
// 构造函数
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 类的方法
void printDetails() {
print('Name: $name, Age: $age');
}
}
void main() {
// 创建一个Person对象并初始化
Person person1 = Person('John', 30);
// 调用类的方法
person1.printDetails();
}
使用例子举例
class Animal {
String name;
Animal(this.name);
void makeSound() {
print('Some generic sound');
}
}
class Dog extends Animal {
String breed;
Dog(String name, this.breed) : super(name);
// 可选地,你也可以在子类中定义自己的构造函数
// Dog(this.breed) : super('DefaultName');
@override
void makeSound() {
print('Bark!');
}
}
void main() {
var myDog = Dog('Buddy', 'Golden Retriever');
print('Name: ${myDog.name}');
print('Breed: ${myDog.breed}');
myDog.makeSound();
}
import 'package:flutter/material.dart';
class Person {
late String firstName;
late String lastName;
// 默认构造函数
Person(this.firstName, this.lastName);
// 命名构造函数
Person.fromFullName(String fullName) {
var parts = fullName.split(' ');
if (parts.length == 2) {
firstName = parts[0];
lastName = parts[1];
} else {
throw ArgumentError('Invalid full name: $fullName');
}
}
// 命名构造函数
Person.fromInitials(String initials) {
var parts = initials.split('.');
if (parts.length == 2) {
firstName = parts[0];
lastName = parts[1];
} else {
throw ArgumentError('Invalid initials: $initials');
}
}
}
使用
void sendMessage() {
// 使用默认构造函数
var person1 = Person('John', 'Doe');
print('Person 1: ${person1.firstName} ${person1.lastName}');//Person 1: John Doe
// 使用命名构造函数
var person2 = Person.fromFullName('Jane Smith');
print('Person 2: ${person2.firstName} ${person2.lastName}');//Person 2: Jane Smith
// 使用另一个命名构造函数
var person3 = Person.fromInitials('A.B');
print('Person 3: ${person3.firstName} ${person3.lastName}');//Person 3: A B
}
要定义重定向构造函数,你可以使用冒号(:)后跟另一个构造函数的调用
在上面的例子中,Person 类有一个主要构造函数,还有两个重定向构造函数:fromName 和 fromAge。这两个重定向构造函数通过调用主要构造函数来完成对象的初始化,从而避免了在每个构造函数中重复相同的初始化代码。
需要注意的是,重定向构造函数中不能包含初始化列表(initializers),因为初始化列表已经在主要构造函数中处理过了。
class Person {
String name;
int age;
// 主要构造函数
Person(this.name, this.age);
// 重定向构造函数
Person.fromName(String name) : this(name, 0);
// 重定向构造函数
Person.fromAge(int age) : this('Unknown', age);
}
void main() {
var person1 = Person('John', 30);
var person2 = Person.fromName('Alice');
var person3 = Person.fromAge(25);
print(person1.name); // 输出: John
print(person2.name); // 输出: Alice
print(person3.name); // 输出: Unknown
}
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
在这个例子中,ImmutablePoint类有一个常量构造函数,它接受两个参数 x 和 y,并且这个类有一个静态常量 origin,它使用了这个常量构造函数来创建一个常量对象。
const ImmutablePoint(this.x, this.y);:这是常量构造函数的定义,它确保 x 和 y 都是常量表达式。
static const ImmutablePoint origin = ImmutablePoint(0, 0);:这是一个静态常量的声明和初始化,使用了常量构造函数创建了一个常量对象。由于 origin 是一个常量,它在编译时就已经被确定了,并且在整个程序的生命周期中都保持不变。
这个例子强调了常量构造函数的两个主要特点:
常量表达式参数: 构造函数的参数以及构造函数本身必须是常量表达式,这里的 (0, 0) 是常量表达式。
静态常量的使用: 常量构造函数通常与静态常量一起使用,以在编译时创建不变的对象,例如 static const ImmutablePoint origin。这样的对象在程序执行期间始终保持不变。
总体而言,这个例子在展示了常量构造函数的基本用法的同时,强调了与静态常量结合使用的重要性。
在Dart语言中,factory是一种特殊的构造函数,用于创建类的实例。与普通构造函数不同的是,factory构造函数并不一定每次都创建一个新的实例。它可以返回一个已经存在的实例,也可以返回一个不同于类的实例。
在你提供的例子中,factory Logger 是一个工厂构造函数,用于创建 Logger 类的实例。这个工厂构造函数使用了一个私有的静态 Map 变量 _cache,用于存储已经创建的 Logger 实例。通过这种方式,工厂构造函数确保相同名字的 Logger 只会被创建一次,以提高效率并节省资源。
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
factory Logger.fromJson(Map<String, Object> json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
void main() {
Logger logger1 = Logger("Logger1");
logger1.log("Hello, Logger1!"); // 输出消息,因为 mute 默认为 false
Logger logger2 = Logger("Logger1");
print(identical(logger1, logger2)); // true,因为相同名字的 Logger 共享同一个实例
Logger logger3 = Logger.fromJson({"name": "Logger3"});
logger3.log("Hello, Logger3!"); // 输出消息,因为 mute 默认为 false
}
Logger(String name) 工厂构造函数
接受一个字符串 name 作为参数。
如果 _cache 中已经存在相同名字的 Logger 实例,它直接返回该实例。
否则,它使用 putIfAbsent 方法将新创建的 Logger._internal(name) 放入 _cache 中并返回。
Logger.fromJson(Map
接受一个包含 ‘name’ 属性的 Map 参数。
使用传入的 ‘name’ 创建一个新的 Logger 实例。
Logger._internal(this.name) 私有构造函数
这是真正创建 Logger 实例的构造函数,但它是私有的,不能直接被外部调用。只能在类内部通过 factory Logger 构造函数调用。
void log(String msg) 方法
用于输出日志消息,但只有在 mute 为 false 时才会输出。 mute 是一个控制是否输出日志的标志。
这是一个简单的例子,说明了 factory 构造函数如何用于创建类的实例,以及如何共享相同名字的实例。
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
double get right => left + width;
set right(double value) => left = value - width;
//一样的写法
void setRight(double value) {
left = value - width;
}
double get bottom => top + height;
set bottom(double value) => top = value - height;
//一样的写法
void setBottom(double value) {
top = value - height;
}
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
print(rect.left == 3); // true 3 == 3
rect.right = 12;
print(rect.left == -8);// true 12 - 20
}
只有声明,唔具体噶实现方法
abstract class Doer {
// 定义实例变量和方法...
void doSomething(); // 定义一个抽象方法.
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供一个实现,所以这里的方法不是抽象的......
}
}
void main() {
Smarttelevision smarttelevision = Smarttelevision();
smarttelevision.turnOn();
}
//父类
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
void _illuminateDisplay() {
print('父类 -> _illuminateDisplay');
}
void _activateIrSensor() {
print('父类 -> _activateIrSensor');
}
}
//子类继承父类
class Smarttelevision extends Television {
void turnOn() {
super.turnOn();//子类可以调用父类的方法
_illuminateDisplay();
_activateIrSensor();
}
//子类重写父类的方法 _illuminateDisplay
@override
void _illuminateDisplay() {
print('子类 -> _illuminateDisplay');
}
//子类重写父类的方法 _activateIrSensor
@override
void _activateIrSensor() {
print('子类 -> _activateIrSensor');
}
}
打印
子类 -> _illuminateDisplay
子类 -> _activateIrSensor
子类 -> _illuminateDisplay
子类 -> _activateIrSensor
<
:小于运算符
void main() {
bool result = 5 < 10;
print(result); // 输出: true
}
+
:加法运算符
void main() {
int sum = 5 + 10;
print(sum); // 输出: 15
}
|
:按位或运算符
8421
--------------
5: 0101
3: 0011
--------------
7: 0111
void main() {
int result = 5 | 3;
print(result); // 输出: 7
}
>>>
:无符号右移运算符
16 8 4 2 1
--------------
16: 1 0 0 0 0
向右移动两位变成
0 0 1 0 0
把二进制转换成十进制
得出: 4
void main() {
int result = 16 >>> 2;
print(result); // 输出: 4
}
>
:大于运算符
void main() {
bool result = 10 > 5;
print(result); // 输出: true
}
/
:除法运算符
void main() {
double result = 10 / 2;
print(result); // 输出: 5.0
}
^
:按位异或运算符
算法规则:位数相同为0,位数不同为1
5: 101
3: 011
--------------
6: 110
void main() {
int result = 5 ^ 3;
print(result); // 输出: 6
}
[]
:获取列表元素运算符
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
int element = numbers[2];
print(element); // 输出: 3
}
<=
:小于等于运算符
void main() {
bool result = 5 <= 5;
print(result); // 输出: true
}
~/
:整数除法运算符(取整
)
void main() {
int result = 10 ~/ 3;
print(result); // 输出: 3
}
&
:按位与运算符
算法规则:位数相同为1,位数不同为0
5: 101
3: 011
--------------
1: 001
void main() {
int result = 5 & 3;
print(result); // 输出: 1
}
[]
=:设置列表元素运算符
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
numbers[2] = 10;
print(numbers); // 输出: [1, 2, 10, 4, 5]
}
>=
:大于等于运算符
void main() {
bool result = 5 >= 5;
print(result); // 输出: true
}
*
:乘法运算符
void main() {
int result = 5 * 3;
print(result); // 输出: 15
}
<<
:左移运算符
5: 1 0 1
向左移动两位
20: 1 0 1 0 0
--------------
16 8 4 2 1
void main() {
int result = 5 << 2;
print(result); // 输出: 20
}
~
:按位取反运算符
5: 00000000000000000000000000000101 (32位表示)
~5: 11111111111111111111111111111010 (按位取反)
~5 将二进制数 00000000000000000000000000000101 的每一位取反,得到 11111111111111111111111111111010。这个二进制数在32位有符号整数表示中对应的十进制值为 -6
void main() {
int result = ~5;
print(result); // 输出: -6
}
-
:减法运算符
void main() {
int result = 10 - 5;
print(result); // 输出: 5
}
%
:取余运算符
void main() {
int result = 10 % 3;
print(result); // 输出: 1
}
>>
:右移运算符
16 16 8 4 2 1
1 0 0 0 0
------------------
0 0 1 0 0
转换成十进制4
void main() {
int result = 16 >> 2;
print(result); // 输出: 4
}
==
:等于运算符
void main() {
bool result = 5 == 5;
print(result); // 输出: true
}