var a = 5和var a = Int(5)有什么区别?

时间:2019-01-03 15:09:08

标签: swift

声明变量时,文字值和整数文字值是否有区别?

4 个答案:

答案 0 :(得分:6)

var a = 5

这将创建一个值为Int的{​​{1}}变量。 Swift从整数文字中推断出5的类型。如果没有其他可用信息,则a是整数文字的默认类型。

Int

这会在var a = Int(5) 上调用一个初始化器,该初始化器具有一个IntInt,该值与上述值一样创建。

要了解有关此初始化程序的更多信息,请将语句更改为:

5

,然后在选项上单击var a = Int.init(5)

您将看到:

  

摘要

     

从给定的整数创建一个新实例。

     

声明

     

init

     

讨论

     

当您使用此初始化程序从另一个整数类型转换时   知道值在此类型的范围内。传递一个值   无法以这种类型表示会导致运行时错误。

因此,您不必要使用已推断为convenience init<T>(_ source: T) where T : BinaryInteger的值来调用Int的初始化程序。正如@RobNapier在他的excellent answer中所解释的那样,额外的调用将由优化程序清除。但是我认为,为什么要打扰?

如果要记录类型,可以显式键入变量:

Int

但是让Swift推断类型:

var a: Int = 5

是首选的方法。

答案 1 :(得分:4)

在优化之前,是的,它们是不同的。 var a = 5立即进行了优化,以便将来引用a的值为5。var a = Int(5)包括对SignedInteger.init的函数调用。您可以通过发出SIL看到这一点:

echo "var x = 5" | swiftc -emit-sil -

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$S4main1xSivp                     // id: %2
  %3 = global_addr @$S4main1xSivp : $*Int         // user: %6
  %4 = integer_literal $Builtin.Int64, 5          // user: %5
  %5 = struct $Int (%4 : $Builtin.Int64)          // user: %6
  store %5 to %3 : $*Int                          // id: %6
  %7 = integer_literal $Builtin.Int32, 0          // user: %8
  %8 = struct $Int32 (%7 : $Builtin.Int32)        // user: %9
  return %8 : $Int32                              // id: %9
} // end sil function 'main'

echo "var x = Int(5)" | swiftc -emit-sil -

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$S4main1xSivp                     // id: %2
  %3 = global_addr @$S4main1xSivp : $*Int         // user: %11
  %4 = metatype $@thin Int.Type
  %5 = metatype $@thick Int.Type                  // user: %11
  %6 = integer_literal $Builtin.Int64, 5          // user: %7
  %7 = struct $Int (%6 : $Builtin.Int64)          // user: %9
  %8 = alloc_stack $Int                           // users: %9, %12, %11
  store %7 to %8 : $*Int                          // id: %9
  // function_ref SignedInteger<>.init<A>(_:)
  %10 = function_ref @$SSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC : $@convention(method) <τ_0_0 where τ_0_0 : FixedWidthInteger, τ_0_0 : SignedInteger><τ_1_0 where τ_1_0 : BinaryInteger> (@in τ_1_0, @thick τ_0_0.Type) -> @out τ_0_0 // user: %11
  %11 = apply %10<Int, Int>(%3, %8, %5) : $@convention(method) <τ_0_0 where τ_0_0 : FixedWidthInteger, τ_0_0 : SignedInteger><τ_1_0 where τ_1_0 : BinaryInteger> (@in τ_1_0, @thick τ_0_0.Type) -> @out τ_0_0
  dealloc_stack %8 : $*Int                        // id: %12
  %13 = integer_literal $Builtin.Int32, 0         // user: %14
  %14 = struct $Int32 (%13 : $Builtin.Int32)      // user: %15
  return %14 : $Int32                             // id: %15
} // end sil function 'main'

但是,一旦对其进行了优化(将-O添加到swiftc行),它们(基本上)就与var a = 5版本相同:

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$S4main1xSivp                     // id: %2
  %3 = global_addr @$S4main1xSivp : $*Int         // user: %6
  %4 = integer_literal $Builtin.Int64, 5          // user: %5
  %5 = struct $Int (%4 : $Builtin.Int64)          // user: %6
  store %5 to %3 : $*Int                          // id: %6
  %7 = integer_literal $Builtin.Int32, 0          // user: %8
  %8 = struct $Int32 (%7 : $Builtin.Int32)        // user: %9
  return %8 : $Int32                              // id: %9
} // end sil function 'main'

后者将为实际上未使用的协议见证者发出大量额外的SIL,但这不会影响最终的二进制文件。

您可以使用Godbolt探索最终的装配输出:

您会注意到,优化的版本完全相同。

实际上,这并不重要。在Swift中,省略类型是很常见的样式,但是在很多情况下需要使用类型,例如UInt或Int64类型,甚至Int()有时也可以使代码清晰。

您将其写成var a: UInt = 5还是var a = UInt(5)只是样式,即使它们导致未优化的输出略有不同。请放心,优化器将轻松为您解决所有这些问题,并以最能解决您问题的方式编写。但是,如果有疑问,请不要理会。这是Swift中的典型首选项。

答案 2 :(得分:3)

let a = 5
print(a)            // 5
print(type(of: a))  // Int
let b = Int(5)
print(b)            // 5
print(type(of: b))  // Int

您只需使用Int类构造函数。第二种方式是隐式的。选择您的第一个选项。

答案 3 :(得分:2)

Swift使用类型推断,并且整数文字被推断为类型Int,因此alet a = 5的类型将为Int。因此,将整数文字传递给Int的初始化程序没有其他作用,因此您的两个示例获得相同的结果。