Swift关键字(mutating)

mutating:只用在值类型中

struct LGStack {
    var items = [Int]()
    func push(_ item: Int) {
        items.append(item)
    }
}

对于结构体而言,我创建了一个items的数组,并且给定LGStack一个push方法,向items数组内append元素,这个时候,会提示错误,很显然不允许我修改items!


截屏2021-01-11 下午6.57.52.png

打开项目文件夹目录

cd /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice

把 mian.swift编译成main.sil并打开(推荐使用vs code)

swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil
No application knows how to open /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice/main.sil.

通过main.si可以看到为什么:

// LGStack.push(_:)
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @guaranteed LGStack) -> () {
// %0 "item"                                      // users: %11, %2
// %1 "self"                                      // user: %3
bb0(%0 : $Int, %1 : $LGStack):
  debug_value %0 : $Int, let, name "item", argno 1 // id: %2
  debug_value %1 : $LGStack, let, name "self", argno 2 // id: %3
  %4 = integer_literal $Builtin.Word, 1           // user: %6
  // function_ref _allocateUninitializedArray<A>(_:)
  %5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %6
  %6 = apply %5<Any>(%4) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // users: %8, %7
  %7 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 0 // users: %20, %17
  %8 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 1 // user: %9
  %9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any // user: %10
  %10 = init_existential_addr %9 : $*Any, $Int    // user: %11
  store %0 to %10 : $*Int                         // id: %11
  // function_ref default argument 1 of print(_:separator:terminator:)
  %12 = function_ref @default argument 1 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %13
  %13 = apply %12() : $@convention(thin) () -> @owned String // users: %19, %17
  // function_ref default argument 2 of print(_:separator:terminator:)
  %14 = function_ref @default argument 2 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %15
  %15 = apply %14() : $@convention(thin) () -> @owned String // users: %18, %17
  // function_ref print(_:separator:terminator:)
  %16 = function_ref @Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> () // user: %17
  %17 = apply %16(%7, %13, %15) : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> ()
  release_value %15 : $String                     // id: %18
  release_value %13 : $String                     // id: %19
  release_value %7 : $Array<Any>                  // id: %20
  %21 = tuple ()                                  // user: %22
  return %21 : $()                                // id: %22
} // end sil function 'main.LGStack.push(Swift.Int) -> ()'

debug_value %1 : $LGStack, let, name "self", argno 2 // id: %3
首先push方法提供默认的参数self,这也是我可以在push方法内访问到items的原因,那么self 就是 LGStack, 是用let进行修饰的,也就是说,是不可变的,这也就是报错的原因

也就是说我在修改items的时候,就是在修改LGStack本身,而且LGStack还是一个let,所以不允许!

通过mutating修饰之后

struct LGStack {
    var items = [Int]()
    mutating func push(_ item: Int) {
        print(item)
        items.append(item)
    }
}

var s = LGStack()
s.push(1)
print(s.items)

lldb打印结果为

1
(lldb) 

那么我在sil面看一下,mutating到底做了什么:

// LGStack.push(_:)
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @inout LGStack) -> () {
// %0 "item"                                      // users: %22, %11, %2
// %1 "self"                                      // users: %23, %3
bb0(%0 : $Int, %1 : $*LGStack):
  debug_value %0 : $Int, let, name "item", argno 1 // id: %2
  debug_value_addr %1 : $*LGStack, var, name "self", argno 2 // id: %3
  %4 = integer_literal $Builtin.Word, 1           // user: %6
  // function_ref _allocateUninitializedArray<A>(_:)
  %5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %6
  %6 = apply %5<Any>(%4) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // users: %8, %7
  %7 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 0 // users: %20, %17
  %8 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 1 // user: %9
  %9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any // user: %10
  %10 = init_existential_addr %9 : $*Any, $Int    // user: %11
  store %0 to %10 : $*Int                         // id: %11
  // function_ref default argument 1 of print(_:separator:terminator:)
  %12 = function_ref @default argument 1 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %13
  %13 = apply %12() : $@convention(thin) () -> @owned String // users: %19, %17
  // function_ref default argument 2 of print(_:separator:terminator:)
  %14 = function_ref @default argument 2 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %15
  %15 = apply %14() : $@convention(thin) () -> @owned String // users: %18, %17
  // function_ref print(_:separator:terminator:)
  %16 = function_ref @Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> () // user: %17
  %17 = apply %16(%7, %13, %15) : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> ()
  release_value %15 : $String                     // id: %18
  release_value %13 : $String                     // id: %19
  release_value %7 : $Array<Any>                  // id: %20
  %21 = alloc_stack $Int                          // users: %22, %28, %26
  store %0 to %21 : $*Int                         // id: %22
  %23 = begin_access [modify] [static] %1 : $*LGStack // users: %27, %24
  %24 = struct_element_addr %23 : $*LGStack, #LGStack.items // user: %26
  // function_ref Array.append(_:)
  %25 = function_ref @Swift.Array.append(__owned A) -> () : $@convention(method) <τ_0_0> (@in τ_0_0, @inout Array<τ_0_0>) -> () // user: %26
  %26 = apply %25<Int>(%21, %24) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout Array<τ_0_0>) -> ()
  end_access %23 : $*LGStack                      // id: %27
  dealloc_stack %21 : $*Int                       // id: %28
  %29 = tuple ()                                  // user: %30
  return %29 : $()                                // id: %30
} // end sil function 'main.LGStack.push(Swift.Int) -> ()'

sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @inout LGStack) -> ()
特别关注这里,给LGStack 添加了一个修饰符@inout(输入输出参数)

debug_value_addr %1 : $*LGStack, var, name "self", argno 2 // id: %3
这里的self的修饰符变成了var,变成了一个可变的self,并且self访问的是一个地址debug_value_addr,而不是原始value的值了debug_value

本质上mutating这个关键字就做了一件事情,默认给结构体LGStack添加了一个intou关键字,这个inout关键字传递的过程中传递的就是所谓的引用

在函数的声明中,默认的参数都是不可变的

func swap(_ a: Int,_ b: Int) {
    let temp = a
    a = b
    b = temp
}

这个代码会出现报错:


截屏2021-01-11 下午7.25.07.png

说明默认参数是不可变的,想要可变,需要添加inout关键字

func swap(_ a: inout Int,_ b: inout Int) {
    let temp = a
    a = b
    b = temp
}

var age = 10
var age2 = 30

//传递的是地址
swap(&age, &age2)

print(age)
print(age2)

这里调用swap函数传递的是地址(&),也就是说inout关键字传递的是地址

注意:
  • mutating:修饰的是方法
  • inout:修改的是参数类型
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容