关于语言不可知:什么是类型安全的?

您所在的位置:网站首页 认证类型错误是什么意思 关于语言不可知:什么是类型安全的?

关于语言不可知:什么是类型安全的?

2024-06-12 15:12| 来源: 网络整理| 查看: 265

"类型安全"是什么意思?

类型安全意味着编译器将在编译时验证类型,如果尝试将错误的类型分配给变量,则抛出错误。

一些简单的例子:

1234// Fails, Trying to put an integer in a string String one = 1; // Also fails. int foo ="bar";

这也适用于方法参数,因为您将显式类型传递给它们:

1234int AddTwoNumbers(int a, int b) {     return a + b; }

如果我尝试使用以下方法调用:

1int Sum = AddTwoNumbers(5,"5");

编译器会抛出一个错误,因为我传递一个字符串("5"),它期待一个整数。

在松散类型的语言中,例如javascript,我可以执行以下操作:

1234function AddTwoNumbers(a, b) {     return a + b; }

如果我这样称呼它:

1Sum = AddTwoNumbers(5,"5");

Javascript自动将5转换为字符串,并返回"55"。这是因为javascript使用+符号进行字符串连接。要使其具有类型感知功能,您需要执行以下操作:

1234function AddTwoNumbers(a, b) {     return Number(a) + Number(b); }

或者,可能:

123456function AddOnlyTwoNumbers(a, b) {     if (isNaN(a) || isNaN(b))         return false;     return Number(a) + Number(b); }

如果我这样称呼它:

1Sum = AddTwoNumbers(5," dogs");

Javascript会自动将5转换为字符串,并附加它们,以返回"5只狗"。

并非所有的动态语言都像javascript一样宽容(事实上,动态语言并不意味着松散的类型语言(参见Python)),其中一些实际上会给你一个无效类型转换的运行时错误。

虽然方便,但它可以让您轻松错过许多错误,并且只能通过测试正在运行的程序来识别。就个人而言,我更喜欢让我的编译器告诉我是否犯了这个错误。

现在,回到C#...

C#支持称为协方差的语言功能,这基本上意味着您可以将基类型替换为子类型而不会导致错误,例如:

123 public class Foo : Bar  {  }

在这里,我创建了一个新的类(Foo),它是Bar的子类。我现在可以创建一个方法:

1 void DoSomething(Bar myBar)

并使用Foo或Bar作为参数调用它,两者都可以正常工作而不会导致错误。这是有效的,因为C#知道Bar的任何子类都将实现Bar的接口。

但是,你不能这样做:

1void DoSomething(Foo myFoo)

在这种情况下,我无法将Bar传递给此方法,因为编译器不知道Bar实现了Foo的接口。这是因为子类可以(通常会)与父类有很大不同。

当然,现在我已经离开了深层次并且超出了原始问题的范围,但它的所有好东西都要知道:)

相关讨论 我觉得这个答案是错误的:类型安全不一定在编译时强制执行。我理解,例如,Scheme被认为是类型安全的,但是会动态检查(类型安全性在运行时强制执行)。这主要是对Benjamin C. Pierce对类型和编程语言的介绍的解释。 你描述的是多态,而不是协方差。协方差用于泛型。 @NicolasRinaudo指出动态语言和静态之间的差距正在被"解释"语言的动态编译和预编译以及"编译"语言中的反射所侵蚀。例如,反射允许运行时鸭子类型,因此编译语言可以说"嘿,这有一个Quack()方法,我会调用它,看看会发生什么"。 Pascal类语言通常也有(可选的)运行时溢出检查,导致运行时发生的"编译器"错误"无法适应提供给8位目标{core dump}的整数"。 您的示例引用了一个名为"强类型"的概念,它与类型安全性不同。类型安全是指语言可以在执行或编译时检测到类型错误。例如,Python是弱类型和类型安全的。这个答案应该被标记为非常误导。 一般说明v。好,但类型安全与强类型不同

不应将类型安全与静态/动态类型或强/弱类型混淆。

类型安全语言是指一个人可以对数据执行的唯一操作是由数据类型宽容的语言。也就是说,如果您的数据类型为X且X不支持operation y,则该语言将不允许您执行y(X)。

此定义不会在选中此选项时设置规则。它可以在编译时(静态类型)或在运行时(动态类型),通常是通过异常。它可以是两者兼而有之:一些静态类型语言允许您将数据从一种类型转换为另一种类型,并且必须在运行时检查强制转换的有效性(假设您试图将Object转换为 - 编译器无法知道它是否可接受。

类型安全并不一定意味着强类型 - 一些语言的名字很弱,但仍然可以说是类型安全。以Javascript为例:它的类型系统虽然很弱,但仍然严格定义。它允许自动转换数据(例如,字符串到整数),但是在明确定义的规则中。据我所知,Javascript程序不会以未定义的方式运行,如果你足够聪明(我不是),你应该能够预测在阅读Javascript代码时会发生什么。

类型不安全的编程语言的一个例子是C:读取/写入数组边界之外的数组值具有规范的未定义行为。无法预测会发生什么。 C是具有类型系统的语言,但不是类型安全的。

相关讨论 什么是类型不安全语言的其他例子?你是什??么意思"在数组边界之外写一个数组值有一个未定义的行为规范。它无法预测会发生什么"。像Javascript一样,它会返回undefined对吗?或者真的发生任何事情。你举个例子吗? @AkshayrajKore肯定。数组是内存指针,因此通过写出界限,你可能会覆盖另一个程序的数据 - 它什么都不做,程序崩溃,导致它擦除你的硬盘 - 它是未定义的,取决于谁在读那些内存以及如何它会对它作出反应。 @Nicolas Rinaudo这不对。你应该读一下虚拟内存。每个进程都有自己的虚拟地址空间,因此进程不能以这种方式"覆盖其他程序数据"。 你是对的 - 这本应该读过你可能会覆盖程序内存的另一部分 - 我相信程序本身包括哪些内容? @NicolasRinaudo程序的代码段在虚拟地址空间中以只读方式映射。因此,如果您尝试写入它会导致分段错误,并且您的程序将崩溃。如果您尝试写入未映射的内存,这将导致页面错误并再次崩溃。但是,如果你运气不好,你可能只是覆盖进程堆栈或堆中的数据(就像其他变量或其他东西一样)。在那种情况下,你可能不会立即崩溃,这甚至更糟,因为你不会注意到虫子,直到(希望)以后! 很好的答案。只是补充一点,Python是另一个众所周知的动态类型的类型安全语言示例。

这里的许多答案都将类型安全与静态类型和动态类型混为一谈。动态类型语言(如smalltalk)也可以是类型安全的。

简短的回答:如果没有操作导致未定义的行为,则语言被认为是类型安全的。许多人认为要严格键入语言所需的显式类型转换,因为自动转换有时会导致明确定义但意外/不直观的行为。

相关讨论 等等,你对类型安全的定义没有单词"type":D if no operation leads to undefined behavior。 另外,我不同意这样的定义。我认为类型安全意味着1.类型的存在2.对编译器的了解,以及适当的检查。

类型安全不仅仅是编译时约束,而是运行时约束。我觉得即便这样,我们可以进一步明确这一点。

有两个与类型安全相关的主要问题。内存**和数据类型(及其相应的操作)。

记忆**

char通常需要每个字符1个字节,或8位(取决于语言,Java和C#存储unicode字符,需要16位)。 int需要4个字节,或32位(通常)。

视觉:

char: |-|-|-|-|-|-|-|-|

int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

类型安全语言不允许在运行时将int插入到char中(这应该抛出某种类型的转换或内存不足异常)。但是,在类型不安全的语言中,您将覆盖3个相邻内存字节中的现有数据。

int >> char:

|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|

在上面的例子中,右边的3个字节被覆盖,因此任何指向该内存的指针(比如3个连续的字符)都会产生垃圾。这会导致程序中的undefined行为(或者更糟糕的是,可能在其他程序中,这取决于操作系统如何分配内存 - 这些日子不太可能)。

**虽然第一个问题在技术上并不是关于数据类型的,但是类型安全语言本身就能解决这个问题,它可以直观地向那些不知道内存分配如何"看起来"的人描述问题。

数据类型

更微妙和直接的类型问题是两种数据类型使用相同的内存分配。取一个int与一个unsigned int。两者都是32位。 (同样容易成为char [4]和int,但更常见的问题是uint与int)。

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

类型不安全语言允许程序员引用正确分配的32位跨度,但是当unsigned int的值被读入int的空间(反之亦然)时,我们再次具有undefined行为。想象一下这可能会导致银行业的问题:

"Dude! I overdrafted $30 and now I have $65,506 left!!"

......当然,银行业务程序使用更大的数据类型。 ;) 大声笑!

正如其他人已经指出的那样,下一个问题是对类型的计算操作。这已经被充分涵盖了。

速度与安全

今天大多数程序员从不需要担心这些事情,除非他们使用像C或C ++这样的东西。尽管编译器尽最大努力将风险降至最低,但这两种语言都允许程序员在运行时轻松违反类型安全性(直接内存引用)。但是,这并非全是坏事。

这些语言计算速度快的一个原因是它们不会在运行时操作(例如Java)中验证类型兼容性。他们认为开发人员是一个很理性的人,他们不会将字符串和int一起添加,为此,开发人员可以获得速度/效率。

"类型安全"的编程语言意味着以下事项:

您无法读取未初始化的变量 您不能将数组索引超出其范围 您无法执行未经检查的类型转换

一个文科专业的解释,而不是一个复杂的科学专业:

当人们说语言或语言特性是类型安全的时,他们意味着该语言将帮助阻止您,例如,将非整数的东西传递给某个需要整数的逻辑。

例如,在C#中,我将函数定义为:

1 void foo(int arg)

编译器将阻止我这样做:

12  // call foo   foo("hello world")

在其他语言中,编译器不会阻止我(或者没有编译器...),因此字符串将被传递给逻辑,然后可能发生一些不好的事情。

类型安全语言试图在"编译时"捕获更多。

在不利的情况下,使用类型安全的语言,当你有一个像"123"这样的字符串并且你想像int一样操作它时,你必须编写更多的代码来将字符串转换为int,或者你有一个int喜欢123,并希望在消息中使用它,如"答案是123",你必须编写更多代码来转换/转换为字符串。

相关讨论 文科专业会说一个解释:)你也在混淆静态打字和动态打字。 文科"专业",而不是"专业"。

为了更好地理解,请观看以下视频,该视频演示了安全语言类型(C#)和非类型安全语言(javascript)的代码。

现在为长文。

类型安全意味着防止类型错误。当一种类型的数据类型被分配给其他类型UNKNOWINGLY并且我们得到不合需要的结果时,会发生类型错误。

例如,JavaScript不是一种类型安全的语言。在下面的代码中,"num"是一个数字变量,"str"是字符串。 Javascript允许我做"num + str",现在GUESS会做算术或连接。

现在对于下面的代码,结果是"55",但重要的是混乱创造了它将做什么样的操作。

发生这种情况是因为javascript不是一种类型安全的语言。它允许将一种类型的数据设置为另一种类型而没有限制。

1234var num = 5; // numeric var str ="5"; // string var z = num + str; // arthimetic or concat ???? alert(z); // displays "55"

C#是一种类型安全的语言。它不允许将一种数据类型分配给其他数据类型。以下代码不允许在不同数据类型上使用"+"运算符。

类型安全意味着以编程方式,变量,返回值或参数的数据类型必须符合特定条件。

实际上,这意味着7(整数类型)与"7"(字符串类型的引用字符)不同。

PHP,Javascript和其他动态脚本语言通常是弱类型的,因为如果你尝试添加"7"+ 3,它们会将(字符串)"7"转换为(整数)7,尽管有时你必须这样做显式(和Javascript使用"+"字符进行连接)。

C / C ++ / Java不会理解,或者将结果连接成"73"。类型安全通过明确类型要求来防止代码中的这些类型的错误。

类型安全非常有用。上述"7"+ 3的解决方案是输入cast(int)"7"+ 3(等于10)。

Type-Safe是仅访问其有权访问的内存位置的代码,并且只能以明确定义的允许方式访问。 类型安全代码无法对对该对象无效的对象执行操作。 C#和VB.NET语言编译器总是生成类型安全的代码,在JIT编译期间验证它是类型安全的。

相关讨论 你的意思是记忆安全吗?

试试这个解释......

TypeSafe表示在编译时静态检查变量以进行适当的赋值。例如,consder是字符串或整数。这两种不同的数据类型不能交叉分配(即,您不能将整数分配给字符串,也不能将字符串分配给整数)。

对于非类型安全行为,请考虑以下事项:

12object x = 89; int y;

如果你试图这样做:

1y = x;

编译器抛出一个错误,表明它无法将System.Object转换为Integer。你需要明确地这样做。一种方法是:

1y = Convert.ToInt32( x );

上面的分配不是类型安全的。类型安全分配是可以直接将类型分配给彼此的类型。

ASP.NET中存在非类型安全集合(例如,应用程序,会话和视图状态集合)。关于这些集合的好消息是(最小化多个服务器状态管理注意事项),您可以在三个集合中的任何一个中放置几乎任何数据类型。坏消息:因为这些集合不是类型安全的,所以当你取回它们时,你需要适当地转换它们。

例如:

1Session["x" ] = 34;

工作正常。但要重新分配整数值,您需要:

1int i = Convert.ToInt32( Session["x" ] );

阅读有关设施可帮助您轻松实现类型安全集合的方法的泛型。

C#是一种类型安全的语言,但要注意有关C#4.0的文章;有趣的动态可能性迫在眉睫(C#实质上是获得Option Strict是一件好事:关闭......我们会看到)。

相关讨论 就个人而言,我讨厌Convert.To表示法,为什么不使用安全演员?它在callstack上的函数调用也很少。

概念:

非常简单类型安全就像意义一样,它确保变量的类型应该是安全的

没有错误的数据类型无法使用整数保存或初始化字符串类型的变量 无法访问超出范围的索引 仅允许特定的内存位置

因此,就变量而言,这完全取决于存储类型的安全性。

类型安全意味着可以分配给程序变量的值集必须符合明确定义和可测试的标准。类型安全变量导致更强大的程序,因为操纵变量的算法可以信任变量只接受一组定义明确的值。保持这种信任可确保数据和程序的完整性和质量。

对于许多变量,可以分配给变量的值集在程序写入时定义。例如,可以允许称为"颜色"的变量采用值"红色","绿色"或"蓝色",而不允许任何其他值。对于其他变量,这些标准可能会在运行时更改。例如,一个名为"color"的变量可能只允许在关系数据库的"Colors"表的"name"列中取值,其中"red","green"和"blue"是三个值对于"颜色"表中的"名称",但计算机程序的某些其他部分可能能够在程序运行时添加到该列表,并且该变量在添加到"颜色"表后可以采用新值。

许多类型安全语言通过坚持严格定义变量类型并仅允许为变量赋予相同"类型"的值来给出"类型安全"的错觉。这种方法存在一些问题。例如,一个程序可能有一个变量"yearOfBirth",这是一个人出生的年份,并且很容易将其类型转换为一个短整数。但是,它不是一个短整数。今年,这个数字小于2009年,大于-10000。但是,随着程序的运行,这一组每年增长1。将其作为"短线"是不够的。使此变量类型安全所需的是运行时验证函数,该函数确保数字始终大于-10000且小于下一个日历年。没有编译器可以强制执行此类条件,因为这些条件始终是问题域的唯一特征。

使用动态类型(或鸭子类型或清单类型)的语言(如Perl,Python,Ruby,SQLite和Lua)没有类型变量的概念。这迫使程序员为每个变量编写运行时验证例程,以确保它是正确的,或者承受不明原因的运行时异常的后果。根据我的经验,使用静态类型语言(如C,C ++,Java和C#)的程序员经常会认为静态定义的类型是他们为了获得类型安全的好处所需要的。对于许多有用的计算机程序来说,这根本不是真的,并且很难预测它是否适用于任何特定的计算机程序。

长短......你想要类型安全吗?如果是,则编写运行时函数以确保在为变量赋值时,它符合明确定义的条件。缺点是它使大多数计算机程序的域分析变得非常困难,因为你必须明确定义每个程序变量的标准。

相关讨论 Python变量是键入的(实际上是强类型的)。尝试这样做,例如:"str"+ 1.你会得到一个错误。但是,在运行时检查类型,而不是编译时。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3