📜  Julia 的类型 |设置 1

📅  最后修改于: 2022-05-13 01:55:18.879000             🧑  作者: Mango

Julia 的类型 |设置 1

Julia 中的类型基本上是各种不同大小和功能的数据元素。程序中的每个值(不是变量)都必然是某种类型。变量只是绑定到某些值的名称。定义值的类型要么由程序员完成,要么由编译器本身完成。在执行源代码之前定义值的类型总是被认为是可行的,以实现快速执行并使您的代码不易出错。

示例:考虑以下三个值:

10 -> Integer,        10.5 -> Float,        10/3 -> Rational

这里的每个值都是不同的类型。整数值不同于浮点值和有理值,类似地,其他两个值彼此不同。现在,如果我们必须添加这三个值或对这些值执行一些其他操作,那么这将是一个困难,因为这些值的类型不同。为了添加这些值,我们需要将其他两个值转换为与第三个值相同的类型。类型系统根据其定义的时间基本上分为两类。这些都是:

  1. 静态类型系统
  2. 动态类型系统

静态类型系统:在静态类型系统中,每个可执行程序表达式在执行之前都定义了一个类型。这是在程序员端完成的,对于更快的代码执行速度是可行的。
动态类型系统:在动态类型系统中,编译器必须在代码编译时决定值的类型。这将导致代码需要一些额外的时间来执行。

Julia 使用动态类型系统来编写变量值,但它也接受静态类型定义,以提供指示某些值属于特定类型的优势。默认情况下,Julia 会为无类型的值分配所需的任何类型。因此,程序员可以编写任何 Julia函数,而无需显式定义类型。但是,为值提供显式类型会提高代码的可读性,并且更容易在代码中发现错误。因此,没有必要在 Julia 中使用 Type 系统,但使用它会使代码更清晰、更简单、更快、更健壮。

类型声明

Julia 中的类型是在::运算符的帮助下声明的。当附加到值或表达式时,此运算符被读取为“是的实例” 。它可以在程序中的任何地方使用,以表明左侧的值是::运算符右侧定义的类型的实例。
声明类型是为了证明断言以确认程序运行良好,并为编译器提供一些关于表达式和值类型的额外信息,这将导致更快和更高效的代码。

现在,您可能会想,如果程序员不知道类型并为值或表达式分配了错误的类型怎么办。这由 Julia 中的异常处理。如果左侧的值不是右侧声明的类型,则会生成异常并且代码执行将停在那里。因为编译器期望左侧的计算值是右侧指定的类型。引发的异常将说明左侧的预期类型(如定义)以及实际产生的类型。
例子:
Julia-Types-01

在上面的代码片段中,可以看出,当左侧的表达式定义为 Float 类型时,它会在执行时生成错误,因为左侧的计算值应为声明的Float64类型,但它是类型为Int64 。后来当类型系统更改为 Int 时,它计算左侧的值并产生输出。

将类型定义与赋值运算符一起使用:当与赋值运算符符一起使用时, ::运算符如果用于使左侧的变量成为类型值,那么它将限制该变量始终保持相同类型的值,就像 C 语言中的静态类型变量一样。分配给变量的每个值,如果不是相同类型,将使用convert函数转换为相同类型。
例子:
Julia-Types-02

Julia-Types-03

Julia 中也允许为函数声明类型。这将导致函数始终以指定类型的形式转换并返回计算值。
例子:

function Addition(x, y)::Float64
    return x + y
end
  
Addition(1, 2)

Julia-Types-04

在上面的代码中,函数应该返回 Integer 值,但由于函数的类型声明,计算值的输出被转换为 Float64(所需类型)。

具体类型和抽象类型

Julia 允许每个对象都有一个类型,但不一定有所有类型的实例。可以具有实例的类型称为具体类型。具体类型不允许有任何子类型。子类型是类型的子实体。如果一个类型可以进一步划分为不同的类型,那么这些部分称为子类型。对于 ex-Strings、Rational、bool 等。
抽象类型是那些存在子类型的类型。例如,Any、Number 等。虽然我们不能创建抽象类型的对象,但在抽象类型的帮助下,程序员可以编写可以处理指定类型的任何子类型的代码。
例子:

function Addition(x::Number)
    return x + 1
end

上面的代码可以接受许多任何子类型,即它将接受 Float64、Int64 等,并以相同的形式返回输出。因为这里x是用::Number输入的,所以 x 必须是 Number 的子类型。如果 x 的值不是 Number 的子类型(如字符串、数组等),则会产生错误。

可以使用<:> 符号来编写类型的子类型。该符号表示左侧is a subtype of 。它也可以在表达式中用于测试左侧操作数是否是右侧操作数的子类型。如果它不是指定类型的子类型,它将返回 true 和 false。
例子:
Julia-Types-05

抽象类型可用于为具体类型提供默认实现。如果我们举一个默认实现是 Any 类型的例子。然后编译器将根据计算的需要将相应的子类型分配给值。

function Addition(x, y)
    return x + y
end
Addition(1, 2)

在执行上述代码时,编译器将自动分配作为函数中值的类型传递的参数的类型。

function Addition(x::Int, y::Int)
    return x + y
end
Addition(1, 2)

具体类型可进一步分为两种:

  • 原始类型
  • 复合类型

原始类型

Julia 中的原始类型是具体类型,其值以位的形式存在。整数和浮点值是原始类型的一个示例。 Julia 有一组预定义的标准原始类型,但它也允许创建您自己的类型。
声明原始类型的语法:

primitive type  end
primitive type   end

原始类型的示例有 Int8、Int16、Int64、Float16、Float32、String 等。

抽象类型不能用于在内存中存储值,编译器会自动为该值分配一个原始类型。如果我们检查抽象类型 Integer 的大小,则会引发错误,因为 Integer 没有固定大小,但我们可以检查其 Primitive 类型的大小,即 Int8、Int16、Int64 等。
Julia-Types-06

复合类型

Julia 中的复合类型是命名字段的集合,可以单独将其视为特定类型的单个值。复合类型可以使用struct关键字声明。
句法:

struct 
    Field_name1
    Field_name2::Type
    Field_name3::Type
end

此处,未指定任何类型的字段设置为默认类型Any 。这种复合类型的对象可以使用构造函数来创建。
例子:

# Creating composite types
struct Geeks
    x
    y::Int64
    z::Float64
end
  
# creating object with constructor
object1 = Geeks("Hello", 10, 10.5)

Julia-Types-07

我们可以看到,在上面的代码中,复合类型是使用 struct 关键字创建的,所有字段都是 Primitive 类型的。如果我们检查使用构造函数创建的对象的类型,那么它会显示已创建的结构。

Julia-Types-08

可变复合类型

如上所述,使用 struct 定义的复合类型是不可变类型。但是,Julia 还允许创建 Mutable 类型的复合类型,这意味着即使在创建之后也可以修改其字段的值。这是通过使用关键字mutable struct来完成的。如果复合类型是用可变结构而不是结构声明的,那么它的实例的值可以随时修改。

mutable struct 
    Field_name1
    Field_name2::Type
    Field_name3::Type
end

例子:

# Creating composite types 
# with mutable struct
struct Geeks
    x
    y::Int64
    z::Float64
end
  
# creating object with constructor
object1 = Geeks("Hello", 10, 10.5)

Julia-Types-09

只需将新值传递给字段即可修改可变结构的值。
Julia-Types-10