“类型安全”是什么意思?


当前回答

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

简单的回答是:如果没有操作导致未定义的行为,则该语言被认为是类型安全的。许多人认为显式类型转换的要求对于严格类型的语言是必要的,因为自动转换有时会导致定义良好但意想不到/不直观的行为。

其他回答

类型安全

在现代c++中,类型安全是非常重要的。类型安全意味着正确使用类型,因此避免不安全的类型强制转换和合并。c++中的每个对象都是根据其类型使用的,并且在使用之前需要对对象进行初始化。

安全初始化:{}

编译器在类型转换过程中防止信息丢失。例如, int {7};初始化没问题 \ . int b{7.5}编译器显示错误,因为信息丢失

不安全的初始化:=或()

编译器不会在类型转换期间防止信息丢失。 int a = 7初始化正常 int a = 7.5初始化正常,但信息丢失。a的实际值将变为7.0 int c(7)初始化OK int c(7.5)初始化是可以的,但是会发生信息丢失。a的实际值将变为7.0

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

简单的回答是:如果没有操作导致未定义的行为,则该语言被认为是类型安全的。许多人认为显式类型转换的要求对于严格类型的语言是必要的,因为自动转换有时会导致定义良好但意想不到/不直观的行为。

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

类型安全语言是这样一种语言,在这种语言中,只能对数据执行数据类型所允许的操作。也就是说,如果您的数据是X类型,而X不支持操作y,那么该语言将不允许您执行y(X)。

这个定义没有设置何时检查的规则。它可以在编译时(静态类型)或在运行时(动态类型),通常通过异常进行。它可以两者兼有:一些静态类型语言允许您将数据从一种类型转换为另一种类型,并且必须在运行时检查转换的有效性(假设您试图将对象转换为消费者—编译器无法知道它是否可接受)。

Type-safety does not necessarily mean strongly typed, either - some languages are notoriously weakly typed, but still arguably type safe. Take Javascript, for example: its type system is as weak as they come, but still strictly defined. It allows automatic casting of data (say, strings to ints), but within well defined rules. There is to my knowledge no case where a Javascript program will behave in an undefined fashion, and if you're clever enough (I'm not), you should be able to predict what will happen when reading Javascript code.

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

概念:

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

没有错误的数据类型,例如不能保存或初始化字符串类型的整数变量 不可访问超出绑定的索引 只允许特定的内存位置

所以这都是关于变量存储类型的安全性。

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

一些简单的例子:

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

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

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

如果我试着称之为使用:

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

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

在一个松散类型的语言,如javascript,我可以做以下:

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

如果我这样调用它:

Sum = AddTwoNumbers(5, "5");

Javascript自动将5转换为字符串,并返回“55”。这是由于javascript使用+符号进行字符串连接。为了使它具有类型意识,你需要做如下的事情:

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

或者,可能是:

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

如果我这样调用它:

Sum = AddTwoNumbers(5, " dogs");

Javascript自动将5转换为字符串,并追加它们,以返回“5只狗”。

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

虽然它很方便,但它会给您带来很多容易被忽略的错误,只有通过测试正在运行的程序才能识别出来。就我个人而言,我更喜欢让编译器告诉我是否犯了这个错误。

现在,回到c#…

c#支持一种叫做协方差的语言特性,这基本上意味着你可以用基类型替换子类型,而不会导致错误,例如:

 public class Foo : Bar
 {
 }

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

 void DoSomething(Bar myBar)

并使用Foo或Bar作为参数调用它,两者都不会引起错误。这是因为c#知道Bar的任何子类都将实现Bar的接口。

然而,你不能做相反的事情:

void DoSomething(Foo myFoo)

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

当然,现在我已经走得太远了,超出了最初问题的范围,但知道这些都是好事:)