函数在 Swift 中是值类型还是引用类型?为啥?

Posted

技术标签:

【中文标题】函数在 Swift 中是值类型还是引用类型?为啥?【英文标题】:Is a function a value type or a reference type in Swift? And Why?函数在 Swift 中是值类型还是引用类型?为什么? 【发布时间】:2018-11-23 16:38:56 【问题描述】:

考虑这个函数:

func addTwoInts(_ a: Int, _ b: Int) -> Int 
    return a + b

这里我将这个函数分配给另一个变量

var mathFunction: (Int, Int) -> Int = addTwoInts

这里addTwoInts是值类型还是引用类型?为什么?

【问题讨论】:

您可以尝试打印两个函数***.com/questions/24058906/…的内存地址,如果相同则为引用,否则为值 【参考方案1】:

闭包和函数都是引用类型。这在 Swift 语言文档中有说明:Closures

【讨论】:

【参考方案2】:

我会说函数类型最适合the definition of a reference type:

引用类型在分配给变量或常量或传递给函数时不会被复制。使用对相同现有实例的引用而不是副本。

但是我不认为这是一个特别有用的区别,IMO 也可以将函数作为值类型的论点(如technically speaking they consist of a pointer and a reference,当函数值传递时两者都被复制)大约)。

更有用的区别是函数具有引用语义,这意味着可以观察实例之间的某种共享状态。这与引用类型不同——值类型可能具有引用语义,而引用类型可能具有值语义。

例如,这是一个具有引用语义的值类型:

var foo = 0
struct S 
  var bar: Int 
    get  return foo 
    nonmutating set  foo = newValue 
  


let s = S()
let s1 = s
s.bar += 1
print(s.bar)  // 1
print(s1.bar) // 1

ss1 共享全局状态,这可以通过改变它来观察。

这是一个具有值语义的引用类型:

final class C 
  let foo = 0


let c = C()
let c1 = c
print(c.foo)  // 0
print(c1.foo) // 0

虽然cc1 共享状态,但这不是直接可观察的,因为共享状态是不可变的。

那么,为什么函数有引用语义呢?因为它们可以包含捕获的变量,这是可以观察到的共享可变状态。

例如:

func makeFn() -> () -> Int 
  var foo = 0
  return 
    foo += 1
    return foo
  


let fn = makeFn()
let fn1 = fn
print(fn())  // 1
print(fn1()) // 2

【讨论】:

【参考方案3】:

闭包和函数都是引用类型

Apple 说:每当您将函数或闭包分配给常量或变量时,实际上是将该常量或变量设置为对函数或闭包的引用。

在下面的示例中,incrementByTen 所指的闭包选择是常量,而不是闭包的内容。

让我们试试看这个例子:

首先我将创建一个以整数为参数的函数,返回一个名为makeIncrementer的函数

func makeIncrementer(forIncrement amount: Int) -> () -> Int 
    var runningTotal = 0
    func incrementer() -> Int 
        runningTotal += amount
        return runningTotal
    
    
    return incrementer

现在 incrementByTen 将引用这个函数的结果。换句话说,引用一个闭包

let incrementByTen = makeIncrementer(forIncrement: 10)

incrementByTen()
// returns a value of 10

到目前为止一切顺利。如果我再次调用 incrementByTen() 会怎样? 结果将是 10 还是 20 ? 是的,你明白了:)它会是 20。因为 闭包和函数都是引用类型,正如我在开头所说的那样。

incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30 with same approach as i explained.

【讨论】:

以上是关于函数在 Swift 中是值类型还是引用类型?为啥?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Swift 中的字符串、数组和字典改为值类型

PHP对象到底是值传递还是引用传递

在 Swift 中检查值或引用类型

如果结构是值类型,为啥我可以新建它? [复制]

Swift - 值类型和引用类型的区别

Java是值传递还是引用传递?