读编程与类型系统笔记04_类型安全

1. 避免基本类型偏执

1.1. 把值声明为基本类型,并对其意义做一些隐含的假定时

1.1.1. 例如:使用number表示邮编

1.1.2. 例如:使用string表示电话号码

1.2. 定义类型来显式捕捉值的含义,从而避免错误解释值

1.2.1. 新类型只是简单地封装了一个数字或字符串

1.2.2. 消除由于不兼容的假定而导致的众多问题

1.2.3. 使代码的可读性变得更好

2. 实施约束

2.1. 通过构造函数实现

2.1.1. readonly,可以保证在构造之后,值会始终有效

2.1.2. 声明为private,并通过一个getter来访问,这样就只能获取该值,不能设置该值

2.1.3. 强制使值有效

2.1.4. 构造函数不返回值

2.1.4.1. 要么完成初始化

2.1.4.2. 要么抛出异常

2.1.5. 应该仅初始化对象的成员

2.2. 通过工厂实现

2.2.1. 场景

2.2.1.1. 不想抛出异常

2.2.1.2. 想返回表示失败的值

2.2.1.3. 构造函数做不到

2.2.1.4. 构造和验证对象的逻辑很复杂

2.2.1.4.1. 构造函数不应该做太繁重的工作

2.3. 基本类型不允许我们直接施加某些限制

2.3.1. 创建新的类型

2.3.1.1. 封装额外的约束

2.3.1.2. 保证不会包含无效的值

3. 添加类型信息

3.1. 类型转换

3.1.1. 一个表达式的类型转换为另一个类型

3.1.2. 有些必须使用额外的代码来完成

3.1.2.1. 显式类型转换

3.1.3. 有些能够由编译器自动完成

3.1.3.1. 隐式类型转换

3.2. 在类型系统之外跟踪类型

3.2.1. Eithe类型

3.2.1.1. 在赋值后,类型检查器不再知道实际的value被存储为TLeft还是TRight

3.2.1.2. 检查this.isLeft()是否为true

3.2.1.3. getLeft()实现执行必要的检查

3.2.1.4. 并按照需要处理无效调用

3.2.1.5. 把值强制转换为对应的类型

3.2.1.5.1. 类型检查器忘记了我们在赋值时提供的类型
3.2.1.5.2. 正确使用时,强制转换是一种很强大的技术,允许我们改进值的类型

3.3. 常见类型转换

3.3.1. 向上转换

3.3.1.1. 将派生类解释为基类

3.3.2. 向下转换

3.3.2.1. 从父类转换到派生类

3.3.2.2. 大多数强类型语言不会自动完成

3.3.2.3. 不是安全的

3.3.3. 拓宽转换

3.3.3.1. 从固定位数的整数类型转换为另外一个更多位数的整数类型

3.3.3.1.1. 如:8位无符号整数转为16位无符号整数

3.3.3.2. 安全的

3.3.4. 缩窄转换

3.3.4.1. 将位数更多的整数转换为位数更少的整数

3.3.4.2. 具有危险性

3.4. 在运行时存储额外的类型信息

3.4.1. 包含一个is操作符

3.4.1.1. 检查某个值是否是特定类型的实例

3.4.2. 其代价是为每个对象实例在内存中存储额外的数据

3.5. 隐藏和恢复类型信息

3.5.1. 同构集合

3.5.1.1. 包含相同类型的项的集合

3.5.1.2. 不需要隐藏类型信息

3.5.2. 异构集合

3.5.2.1. 包含不同类型的项的集合

3.5.2.2. 需要隐藏一些类型信息

posted @ 2023-01-11 08:40  躺柒  阅读(39)  评论(0编辑  收藏  举报