【问题标题】:Swift optional inout parameters and nilSwift 可选 inout 参数和 nil
【发布时间】:2014-07-11 05:37:13
【问题描述】:

是否可以在 Swift 中为函数添加 Optional inout 参数?我正在尝试这样做:

func testFunc( inout optionalParam: MyClass? ) {
    if optionalParam {
        ...
    }
}

...但是当我尝试调用它并传递nil 时,它给了我一个奇怪的编译错误:

Type 'inout MyClass?' does not conform to protocol 'NilLiteralConvertible'

当我的类已经被声明为可选时,我不明白为什么它必须遵守某些特殊协议。

【问题讨论】:

    标签: swift optional


    【解决方案1】:

    它不会编译,因为函数需要引用但您传递了nil。该问题与可选无关。

    通过inout 声明参数意味着您将在函数体内为其分配一些值。怎么给nil赋值?

    你需要这样称呼它

    var a : MyClass? = nil
    testFunc(&a) // value of a can be changed inside the function
    

    如果你知道 C++,这是你的代码的 C++ 版本,没有可选的

    struct MyClass {};    
    void testFunc(MyClass &p) {}
    int main () { testFunc(nullptr); }
    

    你有这个错误信息

    main.cpp:6:6: note: candidate function not viable: no known conversion from 'nullptr_t' to 'MyClass &' for 1st argument
    

    这有点相当于你得到的(但更容易理解)

    【讨论】:

    • 那么我猜答案是。我确信这在 Objective-C 中是可能的。哦,好吧。
    • @chaiguy 也许你可以试试像AutoreleasingPointer<MyClass> 这样的指针。但它是丑陋的国际海事组织。
    • @devios 这在 Objective-C 中绝对是可能的
    • 这就是 nil 有毒的原因
    • Swift 的例子很好,它使之成为可能。
    【解决方案2】:

    其实@devios1 需要的是“可选指针”。 但是在 MyClass 之外?表示“指向可选的指针”。 以下应该在 Swift 4 中工作

    class MyClass {
        // func foo() {}
    }
    
    func testFunc(_ optionalParam: UnsafeMutablePointer<MyClass>? ) {
        if let optionalParam = optionalParam {
            // optionalParam.pointee.foo()
            // optionalParam.pointee = MyClass()
        }
    }
    
    testFunc(nil)
    
    var myClass = MyClass()
    testFunc(&myClass)
    

    【讨论】:

      【解决方案3】:

      这是可能的,它可能与Closure.()有关

      可选项可以有一个 nil 值,但它不期望 nil。因此,如果您只是没有将它传递给函数或传递 MyClass 类型的变量,那么可选将起作用吗?价值为零。就像布莱恩所说的那样。

      当你编写函数时,它必须有一个默认值作为可选参数,如下所示:

      func testFunc(inout optionalParam:MyClass?={var nilRef:MyClass?;return &nilRef}()) {
          if optionalParam != nil {
              ...
          }
      }
      

      通知if optionalParam {...}改为if optionalParam != nil {...}

      你不能在不检查的情况下 uwwrap optionalParam,即if optionalParam? != nil,因为 uwrapping,optionalParam?optionalParam==nil 时失败。 ~注意,var a :MyClass? 在被赋值之前的值为 nil。

      呼叫是testFunc(optionalParam:&amp;a)testFunc(),但绝不是testFunc(nil)

      认为您可能会将两个独立的概念交织在一起,因为它们具有相似的名称、可选参数和可选参数。可选项是具有扩展 nil 条件的变量。可选参数是可选的函数参数。

      进一步阅读here。 Apple 正试图将措辞从可选参数更改为“具有默认值的参数”。不幸的是,他们没有在这些新的可选事物中包含可选参数行为。如果它们在展开时会失败,那么将 nil 可选项作为可选项传递有什么意义。如果它可以在展开之前传递,也许它会更深入地了解这个可选的东西是什么......薛定谔的猫

      【讨论】:

      • 我忘了提到 try BLOCK 中常见的 catch PHRASE 是 if a == nil {a = MyClass();}
      • 不幸的是,这似乎无法在 Xcode 上为我在 Swift 3.0 中编译:我收到错误 '&amp;' can only appear immediately in a call argument list
      【解决方案4】:

      确切的passage from the docs 是:

      您只能将变量作为输入输出参数的参数传递。 您不能将常量或文字值作为参数传递,因为 常量和文字不能被修改。您放置一个 & 号 (&) 当您将变量作为参数传递给变量时,直接在变量名称之前 一个 inout 参数,表示它可以由 功能。

      但是请注意,根据@gnasher 的评论(已编辑),如果您打算或希望允许该实例被另一个实例替换/被另一个实例替换,您只需要将一个类作为 inout(也称为引用)传递,并且不只是修改了原来的。涵盖此内容的文档中的段落是:

      输入输出参数

      变量参数,如上所述,只能在 函数本身。如果你想让一个函数修改一个参数的 值,并且您希望这些更改在函数调用后持续存在 已结束,请将该参数定义为 in-out 参数。

      这里有三个测试,涵盖了 var 和 inout 的用法。

      class Bar : Printable {
          var value = 1
      
          init(_ value:Int) { self.value = value }
          var description:String { return "Bar is: \(value)" }
      }
      
      let bar = Bar(1)
      func changeBarWithoutInoutSinceBarIsAClassYaySwift(b:Bar) { b.value = 2 }
      changeBarWithoutInoutSinceBarIsAClassYaySwift(bar)
      println("after: \(bar)") // 2
      
      var bar2 = Bar(0)
      func tryToReplaceLocalBarWithoutInout(var b:Bar) { b = Bar(99) }
      tryToReplaceLocalBarWithoutInout(bar2)
      println("after: \(bar2)") // 0
      
      var bar3 = Bar(0)
      func replaceClassInstanceViaInout(inout b:Bar) { b = Bar(99) }
      replaceClassInstanceViaInout(&bar3)
      println("after: \(bar3)") // 99
      

      【讨论】:

      • 实际上,inout 与引用(类)的工作方式相同。除了结构的值是结构的所有元素,而引用的值只是引用本身。如果你传递 NSMutableString thisString,你不能将它更改为 NSMutableString thatString,除非你使用 var 或 inout。更改字符不会更改引用。
      • @gnasher,感谢您发布此内容,这更有意义。我相应地更新了我的答案。
      猜你喜欢
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-05
      • 1970-01-01
      • 2018-01-22
      • 2016-07-02
      • 1970-01-01
      相关资源
      最近更新 更多