9.4.2.2 F# 中的向上转换和向下转换(UPCASTS AND DOWNCASTS)

9.4.2.2 F# 中的向上转换和向下转换(UPCASTSAND DOWNCASTS)

如果类型之间的转换不会失败,就称为向上转换(upcast)。我们已经看到,把类型转换成由该类型实现的接口,就是这种情况;另一个示例是把派生类转换成它的基类,在这种情况下,编译器也可以保证操作是正确的,不会失败。

如果有一个基本类型的值,希望将它转换为继承类,操作可能会失败,因为基类的值可能是目标类的值,也可能不是。在这种情况下,我们必须使用第二种类型转换,称为向下转换(downcast)。让我们用一个示例来说明,我们将使用标准的 Random 类,它是从 Object 类派生的(就像任何其他的 .NET 类一样):

> open System;;

> let rnd = new Random();;

val rnd : Random

> let rndObject = (rnd :>Object);;   <-- 成功,操作不会失败

val obj : Object

> let rnd2 = (rndObject :>Random);;                     |

stdin(4,12): error: Type constraintmismatch.              | 向上转换不正确

The type ‘Object‘ is not compatible withthe type ‘Random‘  |

> let rnd2 = (rndObject :?>Random);;   <-- 成功,但可能会失败

val rnd2 : Random

> (rndObject :?> String);;

System.InvalidCastException: Unable to castobject of type

‘System.Random‘ to type ‘System.String‘.

可以发现,如果我们偶然尝试不适当地使用了向上转换,F# 编译器报告这个错误。错误消息说,Object 与 Random 不兼容,这就是说,编译器不能保证 Object  类型的值能够转换到 Random 类型。最后,清单显示,向下转换可能失败,并且,如果试着将对象转换到错误的继承类,会抛出异常。

要想记住 F# 向上转换(>)和向下转换(:?>)的语法,有一个好办法,在使用向下转换时,有一些不确定因素,因为操作可能会失败。这种不确定性是向下转换运算符包含问号,而向上转换不包含的原因。F# 语言还提供了相当于 C# 中 is 的运算符,返回布尔值,说明对象实例是否可以转换为指定的类型。为了测试 obj 是否可以转换为 String,写成 obj :?> String。

在这里,思考一下 F# 和 C# 之间的差异,是值得的。在 C# 中,我们甚至不需要类型转换,如在清单 9.17 中:当编译器知道转换能成功,它不需要消歧,可以让它隐式发生。F# 不进行任何隐式转换,因此,用一个语言结构来表示转换,保证成功,是有道理的。在 C# 中还要使用,就没有什么意义了,所以很少使用,因为两种转换使用相同的语法,更简单。明确指定转换的编程风格,使得类型推断成为可能,而且,通常有助于阐明代码实际上在做什么。

只用一章(合理的大小!)的篇幅,就想讲清所有F# 面向对象的特性,是不可能的,但我们已经知道要把函数式应用程序转变成实际的 .NET 代码,那些是最重要的。

我们已经多次说过,这些改变使 F# 代码更容易在 C# 中访问,因此,现在是证明的时候了,同时,要展示互操作是如何配合的。

时间: 2024-10-06 15:07:09

9.4.2.2 F# 中的向上转换和向下转换(UPCASTS AND DOWNCASTS)的相关文章

多态中的向上转型和向下转型

package ren.redface.demo; /* * 多态中的向上转型和向下转型: * * 引用类型之间的转换 * 向上转型 * 由小到大(子类型转换成父类型) * 向下转型 * 由大到小 * 基本数据类型的转换 * 自动类型转换 * 由小到大 * byte short char --- int --- long --- float --- double * 强制类型转换 * 由大到小 */ public class MethoDemo { public static void main

C++中的向上类型转换和向下类型转换+四种强制类型转换

转自博客:http://blog.csdn.net/wangweitingaabbcc/article/details/7720979# 在c++的世界中有这样两个概念,向上类型转换,向下类型转换,分别描述的是子类向基类,和基类向子类的强制类型转换. 向上强制类型转换 切割:覆盖方法和子类数据丢失的现象生成切割(slice) class Base { public: int b; virtual void Test() { cout << "base" <<en

C++中的向上类型转换和向下类型转换

在c++的世界中有这样两个概念,向上类型转换,向下类型转换,分别描述的是子类向基类,和基类向子类的强制类型转换. 向上强制类型转换 切割:覆盖方法和子类数据丢失的现象生成切割(slice) [cpp] view plain copy class Base { public: int b; virtual void Test() { cout << "base" <<endl; } }; class Derived:public Base { public: in

C++中的虚函数(类的向上转换,和向下转换)

1.C++中的封装是为了代码的模块化,继承是为了代码的重用,而多态则是为了接口的重用.2.C++中的多态是用虚函数来实现的.3.子类对象向父类指针的转换(向上转换)是安全的,隐式的,而父类对象向子类指针的转换(向下转换)是不安全的,用dynamic_cast<>转换会得到一个空指针.4.普通的成员函数会根据指针的类型决定调用哪个函数,而虚函数则会每次都去查虚函数表,根据具体的类对象来决定调用哪个函数. 原文地址:https://www.cnblogs.com/lonelamb/p/113728

3.sql中的向上递归和向下递归

1.向下递归 select * from table_name where 条件 connect by prior bmbm(本级关联条件)=sjbmbm(上级关联条件) start with bmbm(本级关联条件)='610000000000'(本级编码)--包含本级 select * from table_name where 条件 connect by prior bmbm(本级关联条件)=sjbmbm(上级关联条件) start with sjbmbm(本级关联条件)='6100000

Java中的向上造型和向下造型等

package com.study.oop.day01; /** * 如果某个方法是静态 的,它的行为就不具有多态性 * @author LuHongGang * @date 2017年6月5日 * @time 下午4:19:21 * @since 1.0 * 构造函数并不具有多态性,它们实际上是static方法, * 只不过该static声明是隐式的.因此,构造函数不能够被override. */ public class staticDemo { public static void mai

java中的向上转型与向下转型

以前学Javase时就专门注意过这个问题,现在到了现在又犯了这个错误,这个错误让我排查了好久 1 : 向上转型:大体可以理解为子类转换成父类,例子优先还是: 1 public class Animal { 2 public void eat(){ 3 System.out.println("animal eatting..."); 4 } 5 } 7 public class Cat extends Animal{ 9 public void eat(){ 11 System.out.

9.4.2.1 在 F# 中实现接口

清单 9.17 使用 C# 中的显式接口实现,因为,这是 F# 允许的唯一的接口实现的风格.在函数编程风格中,这通常足够了.如果确实需要直接公开类的功能,可以添加额外的.调用相同代码的成员.清单 9.18 显示了前面示例的 F# 版本. 清单 9.18 在类中实现接口 (F#) type CoefficientTest(incomeCoeff,yearsCoeff, minValue) =  [1] let coeff(client) =                             

F#中的隐式转换

我们知道隐式变换在可控情况下会使代码变得简洁.熟悉C#的都知道C#中可以自定义隐式变换,例如 public class A { private int data; public static implicit operator A(int i) { return new A{ data = i}; } } 众所周知,F#本身不会进行任何隐式变换.那F#中是否也可以自定义隐式变换呢? 当然可以.通过定义自己的操作符即可实现. 我们先定义一个转换操作符 let inline (!>) (x:^a)