当前位置: 首页 > 网络应用技术

Scala通用的Liskov哲学

时间:2023-03-07 03:11:03 网络应用技术

  当我们学习Java时,我们已经与通用类型的概念接触。当我们不确定某个类型的某个参数是哪种类型时,我们将使用通用类型来替换。通用类型最常用于集合集合中的最常用,说“什么元素是加载”集合。

  同时,为了限制这种通用类型,我们已经开发了上限的概念和通用类型的下限(也称为类型约束)。,也可以通过查看和上下文定义来实现约束的类型。这两种方法主要与之前学到的隐藏转换和隐藏值有关。

  另外,继承和继承与设置功能之间存在关系,我们可以,我们可以考虑该函数可以替换的函数,或者我们可以识别子功能吗?首先,这是Scala中的YES。作者将介绍为什么这是从更换李的原则的角度理解的原因。

  Java使用Sprite括号(有些人也称其为Diamond符号)来定义仿制药(Scalas通常称为Scala中的“类型参数”,但意思是相同),而Scala使用中型括号来表示通用。消息类并定义其中包含的信息类型为通用类型。

  无论是定义通用还是定义的通用方法,都写在参数列表之前。

  作者的基本用法在这里没有详细说明。在这里,我们专注于引入Scala的类型约束。

  类型约束分为上限和下限。

  在Java的通用机制中,如果某个通用类型是A型(或A是上边界)的子类型,则其语法为:.Scala使用它来指示(类似于逻辑)。在添加中,添加的符号,Java在Scala中代表。

  现在,尝试使用Scala编写一种常见的比较方法,它可以比较实现接口的类实例。

  在主函数中调用此功能,并传递两种类型的实例:

  此处未使用Scala的类型,因为Scala中的类型未实现接口(这是Java类别的内容,Scala使用该特征)。Java包装类实现接口。因此,调用此功能时,我们需要使用以下方法来指示在调用此方法之前,将Scala类型转换为所有隐藏类型。

  在Java的通用机制中,如果某个通用类型是A型的母体类型(或A是通用的下边界),则其语法为:.scala用于指示(类似于逻辑)。

  使用下边界有时会触发不可接受的现象。我们首先声明四个类别:动物(),bird(),parrot()。这三个具有继承关系,并且还有一个无关的汽车()。

  主函数中定义了一个通用函数,如下所示:

  显然,我们规定了这种遗传类型的下限。基于直觉,我们安装的元素至少应为或类型。以下写作:

  实际上,此代码是正确的。执行结果是:

  上述代码中哪种类型?打开交互式终端repl,输入以上所有语句,然后执行以下代码:

  执行此代码后,它将返回:

  从反思的结果来看,当我们引入的实例时,应将其视为上层转换对象,因此程序没有错误。

  在上一篇文章中,它提醒人们,当操作中的转换对象(由于Java的动态绑定机制)时,该程序始终选择最“特定”的方法。。

  编译器将直接指出错误:无法解析该方法。重新显示当前考虑使用此类型。

  显然,为了维持此列表的兼容性,必须在同一类型之间选择遗传类型,并且很明显,并非所有动物都有方法。:目前,它只能是最抽象的类型。

  在这种情况下,它不能被调用。

  根据上一节的现象,作者给出了以下衍生物:

  视图和上下文的视图定义为属于Scala的唯一类型。不仅如此,这里还有很多隐藏的转换技术。在本章示例的开头,我们将不再使用Java和接口来实现比较功能,并用Scala和特征替换它。

  视图所定义的符号是“ viw界限”。它的使用范围比通用符号更大。如果存在,它可能不是严格继承的子类别,因为我们可以间接提供来自来自scenery的隐藏转换函数的“”关系。

  与先前生成的上限不同,视图定义的概念更接近:使用隐藏的转换功能将某些类型的非匹配类型转换为适应类型(类似于适配器模式)。

  让我们以下面的示例为例,如何直接比较$ 3至20元之间的大小在$ 3到20元之间。无论如何,无论是什么货币,它们的价值总是链接到另一个项目 - 也就是黄金。您想比较不同价值的货币,您只需要将它们转换为同等的黄金,然后比较哪个方可以交换更多黄金以解释问题。

  某些模板类的定义如下:

  其中,仅实现了特征,因此只能将属性与彼此进行比较。此外,特征的特征与Java的性质相同。此外,可以直接使用在接口中使用的任何类。

  下面定义了另一种方法。它判断以前的货币是否比后者更有价值(或同等) - 如何将黄金换成多大的判断。

  其中,这意味着允许其他没有价格比较功能的类,例如此代码块中的类中的类,转换为比较的等效物。这要求我们提供相应的隐藏转换功能:

  在此代码中,我们使用模式匹配来完成不同类型货币的黄金交换功能。

  然后,您可以使用方法比较不同类型的货币。当然,比较可以是任何其他类型。只要提供相应的隐藏转换功能将其转换为它,他们就可以比较其“值”大小。

  推荐的写作代码将没有任何问题要运行,但是编译器仍将弹出警告。原因是它也尊重视图等效于隐式参数的写作。我们刚才定义的最佳定义:

  这种写作公开了隐式参数的参数列表。对于代码的呼叫者,他可以主动自定义该函数的详细信息,而不是依靠定义域中提供的隐藏转换功能。

  上下文定义的符号是表单的形式]。尽管它仅与上边界符号不同,但它代表了一个完全不同的概念:上下文定义它取决于隐藏的值(或下面)以给出一个和一些调用的功能。

  从一个特定的示例开始。deak a函数:它用于比较两个对象,并返回一个年龄较大的对象(两个对象在同一年龄段返回到前者)。

  这是一个简单的示例类。

  方法需要接收一个比较器,该比较器由我们自己实现。由于仅需要全局比较,因此在此处使用关键字创建一个示例对象。

  现在,该方法可以自动比较正确的比较。

  显然,可以汇总此方法,因为它不限于比较类别。实际上,对于任何类型,该方法只需要确保可以接收上下文中提供的比较规则,并且该方法可用于正常操作。上下文的使用定义了此逻辑可以轻松表达此逻辑,并且它必须以书面形式更加简洁。

  这里没有隐藏参数的列表,因此如何调用函数中的隐藏值?所有隐藏的转换都将在编译期间完成绑定,而Scala提供了积极地获得类型的隐式值以满足该类型的类型定义域。从上面的代码判断,我们获得了比较器。

  设置了父类,还有另一个通用类,并给出了不变,逆和协调的定义。

  不变*(不变)*,即下属关系继承的继承和继承的顺序。

  合作*(协变)*,即,父母阶级,继承和继承的命令。

  反射*(违反)*,即父级。继承顺序和继承顺序相反。

  在这里,数字和数字是指打字的转换。它们只能用于通用类,而不是用于通用方法,因为我们说的类型(协作和逆变器),不变概念的概念是描述类型参数并包含其通用类。此外,可以将投注的类型与上限和下限符号一起使用。

  让我们不改变例子。

  现在,当我们开始使用Scala代码时,您可以尝试以下三种情况。首先给出三个非常简单的类:

  如果这个盒子没有变化:

  如果此框是协调的更改:

  如果此框倒置:

  如果类包含多个通用参数,则可能同时逆变器与协调之间存在关系,例如:

  它说,随着连续的继承,它将变得更加抽象(越接近它),并且会变得更加具体。因此,Scala引入协作更改的意义是什么?简单地说,Scala希望提供功能可以“继承和扩展”功能以实现“更大的FP”的功能。

  liskov替换王子*:如果您可以在需要类型的任何地方使用类型替换,则可以安全地相信它是一种sub -type.in oop程序,RILI替换的原理是最常用的,并且更易于理解。例如,以下Java代码:

  显然,这是一个上层变换对象。它使用更强大的子类,而不是实现父类的功能(实际上是接口)。明显地,可以完成所有需要的功能。它符合更换Li的原则,因此不会带来任何问题。

  但是,在需要的情况下,更抽象的是一个不安全的代码。原因是该程序可能取决于子类以提供更多的功能,但可能无法提供父级。除非放置更详细的代码在母班上,该程序本身违反了OCP打开和关闭的原则,并且不符合逻辑理解。

  在FP编程中,以下表示丰富的替代原理的理念:如果函数可以实现与函数相同的函数,并且只需要更多的抽象参数,我们就可以提供更具体的值。然后,我们可以认为函数是函数是函数的子型,或者该函数比函数函数更“功能”。在Scala中,不仅是转换的对象,而且还要“向上转换”。功能”。

  作者临时使用一个简单的符号来表示“ sub -function”:使用,...表示可能出现在函数参数列表中的类型,...表示可能出现在返回值中的类型一个函数,设置它,设置它,但是在它们中,上级父类代表相应的类型,较低级别的子类代表相应的类型。

  显然,这里的参数类型提出了两个现象:

  清楚地说:

  如果我们需要定义具有上述继承关系的功能接口,则应该这样:

  在此类的描述中,该函数的所有参数列表出现在逆变器中,因此在这里也称为逆变器点。类似地,所有出现在返回值中的人都是协调的,因此返回值也称为协作点。

  编译器将检查您的程序:如果出现在逆变器点中的参数是协调的,或者应在协作点中出现的参数倒置,则表明您有一个错误:

  为什么编译器拦截了这一点?因为这两种情况违反了功能之间的Lishi替换原则:

  这样的原则符合程序员的“贪婪策略”:当他不知道哪种参数需要接受功能时,他肯定只想传递到最常见的类型,这可以使此功能正常工作。这样,为了获得正确的呼叫结果,编程制造商不必被迫追求类型参数的详细信息。

  更“贪婪”的是,程序员希望该函数的返回值完成。,程序员无需执行强制性项目或强制性转换。

  在以下类型定义链接中,对于不涉及更改类型的类型参数,其将是相同的位置,或者将不再接收或合作的参数类型(以后有一些内容)。

  在这里,为了尝试可能的情况和错误,此处设计的协调是“故意的”。我们不会暂时讨论任何对这种说法的实际用途,而只能分析编译器是否会报告错误。

  也有特殊情况。如果某种参数类型出现在参数列表中并同时返回值,并且还符合Li的替换原则的规则,也就是说,您要传递更多的抽象,并且输出可以加载更详细的类型。我现在做吗?

  我们无法做到这一点,因为它会含糊不清,但是我们可以选择等效的替代方法,即使您使用另一个符号替换了其中一种情况,例如替换符号之间的协同关系:

  相反,使用等效符号替换相同效果之间的协调关系的使用也是可行的:

  在大多数情况下,等效替换应表示相同的语义,但不在这里。在这种转换中,可以理解出现在功能的合作点位置。同样的行为行为引起了冲突。有两个原因:

  显然,“期望”和listbuffer本身的定义彼此相反,因此编译器将报告错误:它不支持协作更改的特征的安装,或者它以恒定点出现。

  在较早的示例中,为什么不报告错误?它非常简单且没有变化。它出现在随后的任何反转点,协作点,并且在不变点没有问题。

  以下是一个易于理解的“积极示例”:类型的类型参数是协调的,以及同时出现的协调点。因此,它行不通。

  如果您想保持协同作用改变以保持遗传遗传关系(或符合李更换的原则),请记住5分:

  最后引用了一张图片生动地描述这种关系:

  下面有三种原材料(根据继承的顺序):,,和三个产品(按继承的顺序):

  声明具有类型参数的工厂类,其原材料和产品是上述六种类型。工厂取决于受上限限制的原材料和产品。Richea的替代品并演示了如何安全地将工厂实例的类型分配给该类型。

  下面给出的声明:

  主要功能如下:

  compareval [java.lang.integer](31,21)1作者:huahuazi