swift2.2当中的inout参数的使用

在Swift中,初次接触inout关键字以及它的用法,可能会让我们想起C/C++中的指针,但实际上Swift中inout只不过是按值传递,然后再写回原变量,而不是按引用传递:

An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.

这样的好处在于它远比使用引用安全。首先举个最简单的例子看一看inout关键字怎么用:

func inc(inout i: Int) {
    ++i
}

var x = 0
inc(&x)
print(x)    // 输出结果:“1”

参数x传入到inc函数中后,在函数内被修改为1,函数返回时这个值(1)覆盖了原来的x的值(0),所以x变成了1。

对比一下另一种同样能在函数内部改变变量值的实现方式——闭包:

func inc() -> () -> Int {
    var i = 0  //在inc函数内定义变量i
    return { ++i }  // 闭包中截获变量i
}

let f = inc()
print(f()) // 输出结果:“1”
print(f()) // 输出结果:“2”

闭包是通过截获外部变量的引用从而实现对变量的修改的,我们通过闭包来证明,inout参数是按值传递的:

func inc(inout i: Int) -> () -> Int {
    return { ++i }  // 闭包中截获inout参数i
}

var x = 0
let f = inc(&x)
print(f()) // 输出结果:“1”
print(x) // 输出结果:“0”

如果inout参数是按引用传递,因为我们知道闭包会按引用截获变量,所以闭包内的++i语句实际上会影响到我们定义的变量x,因此最后一个输出的结果应该是1,但实际上运行结果是0。

这说明inout参数是按值传递的,我们梳理一下整个过程:

  • 首先变量x的值是0,它作为inout参数传入inc方法中,inc方法内有一个x的副本,闭包截获了这个副本的引用。
  • 随后inc方法方法返回,此时的副本值还是0,所以外部的变量x的值为0。
  • 接下来我们调用闭包,副本值被改为1,但是外部的变量x的值不会受到任何影响,所以它依然为0。

如果在inc方法中返回闭包之前就调用这个闭包,那么外部的变量x的值就会被修改为1,这是因为在函数返回前,副本的值变成了1:

func inc(inout i: Int) -> () -> Int {
    let f = { ++i }  // 闭包中截获inout参数i
    f()
    return f
}

var x = 0
let f = inc(&x)
print(x) // 输出结果:“1”

&并不总表示inout

如果在函数声明中,参数是一个UnsafeMutablePointer的指针,那么传递参数的时候也要加上&,这和inout参数看上去用法类似,但实际上这里是按引用传递而不是按值传递。我们可以改写一下之前的inc方法:

func inc(i: UnsafeMutablePointer<Int>) -> () -> Int {
    //函数内存储指针i的副本,闭包截获这个副本
    return {
        i.memory++
        return i.memory
    }
}

这个方法的使用与之前类似。有兴趣的读者可以自行尝试。这里我们换一种调用方式,传入inc方法的参数不是整数地址,而是数组的地址:

let f: () -> Int
do {
    var x = [0]
    f = inc(&x)
}
print(f())
时间: 2024-08-07 21:18:40

swift2.2当中的inout参数的使用的相关文章

MySQL 存储过程传参之in, out, inout 参数用法

存储过程传参:存储过程的括号里,可以声明参数. 语法是 create procedure p([in/out/inout] 参数名  参数类型 ..) in :给参数传入值,定义的参数就得到了值 out:模式定义的参数只能在过程体内部赋值,表示该参数可以将某个值传递回调用他的过程(在存储过程内部,该参数初始值为 null,无论调用者是否给存储过程参数设置值) inout:调用者还可以通过 inout 参数传递值给存储过程,也可以从存储过程内部传值给调用者 如果仅仅想把数据传给 MySQL 存储过

Swift中什么时候用变量参数、inout参数

首先要明白一般的常量参数:函数中的参数在函数内不能进行运算的参数是常数参数.苹果声明一个函数,对一个参数的默认行为就是这个参数是不允许修改的.默认参数是一个let值的参数. 变量参数:当传入参数时候,在函数体内可以修改这个传入的参数时,需要变量参数,变量参数需要在声明函数时参数处加上var,这也是其他语言参数的一般类型. inout参数:在函数内对参数进行修改之后,在函数外部参数如果也发生了变化,则这个参数为inout参数 //使用inout传入参数的值是切切实实会改变的 func swapTw

mysql存储过程中in、out、inout参数使用实际案例

1.参数in的使用(代表输入,意思说你的参数要传到存过过程的过程里面去)//为了避免存储过程中分号(";")结束语句,我们使用分隔符告诉mysql解释器,该段命令是否已经结束了./**案例功能:求1-n的和开发者:徐守威时间:2016-08-13*/delimiter $create procedure p1(in n int)begin declare total int default 0; declare num int default 0; while num < n d

Swift - 31 - 常量参数, 变量参数和inout参数

//: Playground - noun: a place where people can play import UIKit // swift中默认情况下, 传入的参数是不可以修改的, 也就是let类型, 也就是常量参数 // 如果想修改这个参数的值, 需要在参数前加"var", 也就是变量参数 func toBinary(var num:Int) -> String // 将一个数转换为二进制 { var result = "" while num !

mysql存储过程中in、out、inout参数使用

in 代表输入,意思说你的参数要传到存过过程的过程里面去.基本可以理解为传入function的参数,而如果该参数是个变量,那么整个procedure过程结束后,不会影响外部的变量值. /案例功能:求1-n的和开发者:徐守威时间:2016-08-13/delimiter $create procedure p1(in n int)begindeclare total int default 0;declare num int default 0;while num < n doset num:=n

Python 函数当中的不定参数 *args 和**kwargs 姐妹花

*args 和**kwargs,*args 可以当作可容纳多个变量组成的list ,而**kwargs可当做容纳多个key和value的dictionary ,所以*args 没有key值,**kwargs有key值. 举个例子:def test_args(*args): print(args) def test_kwargs(**kwargs): print(kwargs) if __name__ == '__main__': test_args(1,2,3,4)#输出结果是(1, 2, 3,

MySQL 存储过程参数用法 in, out, inout

MySQL 存储过程参数有三种类型:in.out.inout.它们各有什么作用和特点呢? 一.MySQL 存储过程参数(in) MySQL 存储过程 “in” 参数:跟 C 语言的函数参数的值传递类似, MySQL 存储过程内部可能会修改此参数,但对 in 类型参数的修改,对调用者(caller)来说是不可见的(not visible). drop procedure if exists pr_param_in; create procedure pr_param_in ( in id int

Swift2.2新特性

1.编译期Swift版本检测 #if swift(>=3.0) print("Running Swift 3.0 or later") #else print("Running Swift 2.2 or earlier") #endif 它和Swift2中介绍过的#available表达式不同,#available表达式是运行时检查,#if swift(>=3.0)... #else... #endif是编译期检查. 一个警告:这个特性这次不可用,因为S

笔记:MyBatis Mapper XML文件详解 - 映射和参数

MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码.MyBatis 就是针对 SQL 构建的,并且比普通的方法做的更好. SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 给定命名空间的缓存配置. cache-ref – 其他命名空间缓存配置的引用. resultMap – 是最复杂也是最强大的元素,用来描述