声明变量时,文字值和整数文字值是否有区别?
答案 0 :(得分:6)
var a = 5
这将创建一个值为Int
的{{1}}变量。 Swift从整数文字中推断出5
的类型。如果没有其他可用信息,则a
是整数文字的默认类型。
Int
这会在var a = Int(5)
上调用一个初始化器,该初始化器具有一个Int
值Int
,该值与上述值一样创建。
要了解有关此初始化程序的更多信息,请将语句更改为:
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
,因此a
中let a = 5
的类型将为Int
。因此,将整数文字传递给Int
的初始化程序没有其他作用,因此您的两个示例获得相同的结果。