Golang切片参考混乱

时间:2018-12-28 03:24:52

标签: go

package main

import (
    "fmt"
)

func main() {
    values := make([]int, 0, 100)
    val := make([][]int, 2)
    for i:=0; i<2; i++ {
        values = values[:0]
        for j:=0; j<2; j++ {
            values = append(values, i+j)
        }
        val[i] = values
        fmt.Println(values, val) //
    }
    fmt.Println(val)
}

https://play.golang.org/p/5x60VfDXbFw

追加分片时,val应该为[[0,1],[1,2]],但得到[[1,2],[1,2]]

3 个答案:

答案 0 :(得分:1)

发生这种情况是因为切片val包含指向其子切片的指针,而不是子切片本身的指针。在代码中,您最初将指向values的指针放在位置val[0]中。然后,您修改values,然后在values中将指针设置为val[1]。但是val[0]val[1]都指向同一个基础对象(values),该对象已被修改。

您可以通过在外循环的每次迭代中创建一个新的values切片来解决此问题,这样val的每个子切片将是一个不同的切片。

例如:

func main() {
    val := make([][]int, 2)
    for i:=0; i<2; i++ {
        values := make([]int, 0, 100)
        for j:=0; j<2; j++ {
            values = append(values, i+j)
        }
        val[i] = values
        fmt.Println(values, val) //
    }
    fmt.Println(val)
}

fmt.Println的输出:

[0 1] [[0 1] []]    // values, val
[1 2] [[0 1] [1 2]] // values, val
[[0 1] [1 2]]       // val

答案 1 :(得分:1)

切片功能:

  

切片包含对基础数组的引用,如果您分配一个,   切片到另一个,都指向同一个数组。

slice的值将是您最后一次修改它的值。因此,这是实现目标的两种方法。

使用复制

import UIKit
import AVFoundation
import UserNotifications

let center = UNUserNotificationCenter.current() // usernotification center

class ViewController: UIViewController, UNUserNotificationCenterDelegate {
    var timer = Timer()
    var isGrantedAccess = false
    var player: AVAudioPlayer?
    var passingDate : Date?
    @IBOutlet var dptext: UITextField!
    let datePicker = UIDatePicker()
    @IBOutlet var taskIDo: UITextView!

    override func viewWillAppear(_ animated: Bool) {

        center.delegate = self
        createDatePicker()
        timer  = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(testDate), userInfo: nil, repeats: true)

    }

    func playSound() {
        let url = Bundle.main.url(forResource: "fc", withExtension: "mp3")!
        do {
            player = try AVAudioPlayer(contentsOf: url)
            guard let player = player else { return }

            player.prepareToPlay();player.play()} catch let error as NSError {print(error.description)}}


    func createDatePicker() {
        datePicker.datePickerMode = .dateAndTime
        let toolbar = UIToolbar()
        toolbar.sizeToFit()

        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressed))
        toolbar.setItems([doneButton], animated: false)

        dptext.inputAccessoryView = toolbar;dptext.inputView = datePicker
    }

    @objc func testDate() {
        print("in testDate")
        if Calendar.current.isDate(datePicker.date, equalTo: Date(), toGranularity: .minute) {
            if let passingDate = passingDate, Calendar.current.isDate(datePicker.date, equalTo: passingDate, toGranularity: .minute)
            {
                print("in return")
                return
            }

            passingDate = datePicker.date

            let content = UNMutableNotificationContent()
            content.badge = true
            content.title = "Test"
            content.body = "Lets Roll!"
            content.sound = UNNotificationSound.default

            let t = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: true)
            let r = UNNotificationRequest(identifier: "any", content: content, trigger: t)

            UNUserNotificationCenter.current().add(r, withCompletionHandler: { (error) in
                dump(error)
            })

        }
    }

    @objc func donePressed() {

        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .short
        dateFormatter.timeStyle = .short
        dptext.text = dateFormatter.string(from: datePicker.date)
        self.view.endEditing(true)

    }
}

每次在第一个for循环中使用新值

func main() {
    values := make([]int, 0, 100)
    val := make([][]int, 2)
    for i := 0; i < 2; i++ {
        values = values[:0]
        for j := 0; j < 2; j++ {
            values = append(values, i+j)
        }
        val[i] = make([]int, 2)
        copy(val[i], values)
        fmt.Println(values, val) //
    }
    fmt.Println(val)
}

答案 2 :(得分:0)

您应该在for循环values = []int{}

中初始化值

这样的代码:

package main

import (
    "fmt"
)

func main() {
    var (
        valLength = 2
    )
    val := make([][]int, valLength)
    for i := 0; i < valLength; i++ {
        values := []int{}
        for j := 0; j < 2; j++ {
            values = append(values, i+j)
        }
        val[i] = values
        fmt.Println(values, val) //
    }
    fmt.Println(val)
}

您只需更改变量valLength即可获得所需长度的切片。