Contoh aplikasi Cobra ini, https://github.com/kurtpeek/myCobraApp, berisi scaffolded aplikasi Cobra menggunakan generator Cobra dengan perintah berikut:

cobra add serve
cobra add config

Struktur direktori adalah

.
├── LICENSE
├── cmd
│   ├── config.go
│   ├── root.go
│   └── serve.go
├── go.mod
├── go.sum
└── main.go

Dalam config.go, variabel string deviceUUID didefinisikan dan diikat ke flag untuk perintah tersebut dengan nilai default "configDeviceUUID":

var deviceUUID string

func init() {
    rootCmd.AddCommand(configCmd)

    // Cobra supports local flags which will only run when this command
    // is called directly, e.g.:
    configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
    fmt.Println("deviceUUID after config init:", deviceUUID)
}

Demikian pula, dalam serve.go variabel deviceUUID terikat ke bendera lokal:

func init() {
    rootCmd.AddCommand(serveCmd)

    serveCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "serveDeviceUUID", "Device UUID")
    fmt.Println("deviceUUID after serve init:", deviceUUID)
}

Masalahnya adalah jika saya menjalankan perintah config tanpa menentukan tanda deviceUUID di baris perintah, perintah tersebut mengambil nilai default dari perintah serve:

> go run main.go config
deviceUUID after config init: configDeviceUUID
deviceUUID after serve init: serveDeviceUUID
deviceUUID: serveDeviceUUID
config called

Apa yang tampaknya terjadi adalah fungsi init() di setiap file dijalankan dalam urutan abjad, dan yang terakhir dijalankan menetapkan nilai default untuk flag.

Bagaimana saya bisa menghindari perilaku ini? Saya ingin nilai default yang ditetapkan dalam config.go untuk selalu diterapkan pada perintah config. (Tentu saja saya dapat mendeklarasikan variabel terpisah seperti configDeviceUUID dan serveDeviceUUID, tetapi bagi saya ini agak berantakan).

1
Kurt Peek 28 Februari 2020, 04:09

1 menjawab

Jawaban Terbaik

Saya tidak tahu mengapa Anda menganggap itu berantakan. Anda memiliki satu variabel, dan Anda menyetelnya dalam beberapa fungsi init, jadi setelan terakhir adalah yang tetap disetel: penjelasan Anda tentang apa yang terjadi adalah benar. Jelas, ini sebenarnya dua variabel yang berbeda, hanya saja paling banyak salah satunya akan digunakan.

(Dengan asumsi ada perintah lain yang melakukan hal lain, mungkin tidak ada variabel global ini yang akan digunakan. Jika Go adalah bahasa yang lebih dinamis secara alami di mana semuanya diputuskan saat runtime, atau jika Anda menggunakan pengaturan runtime yang lebih dinamis, Anda tidak dapat membuat semuanya. Tapi itu bukan Go: Go penuh dengan pengetikan statis dan variabel statis, dibuat pada waktu tautan.)

Namun, jika Anda benar-benar ingin menggunakan hanya satu variabel global, solusi yang jelas adalah memilih beberapa nilai sentinel yang berarti tidak disetel, dan menjadikannya nilai default yang ditetapkan Cobra. Kemudian, jika variabel memegang nilai "not set" saat menjalankan perintah, Anda tahu bahwa pengguna tidak memberikan nilai.

Jika string kosong cocok sebagai penjaga seperti itu—biasanya begitu—ini mudah. Setiap perintah Anda mendapatkan beberapa baris:

if deviceUUID == "" {
    deviceUUID = defaultDeviceUUID
}

Dan Anda sudah selesai.

Mungkin agak menyenangkan, atau setidaknya lebih nyaman bagi Anda, jika kode kobra menyimpan nilai penginisialisasi default di suatu tempat pribadi ketika Anda melakukannya:

configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")

Dan kemudian menyalin nilai-nilai default pribadi yang disimpan ke dalam variabel global (tunggal) ketika perintah tingkat atas memutuskan bahwa sub-perintah config akan digunakan, daripada tidak menyimpannya di suatu tempat pribadi, dan menyalinnya ke dalam variabel global (tunggal) di pada saat fungsi configCmd.Flags().StringVar() dipanggil, tetapi sebenarnya bukan itu cara kerjanya. Jadi:

configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "", "Device UUID")

Ditambah tes string kosong di atas mungkin cukup. Perhatikan bahwa setiap init masih menimpa variabel global (tunggal, bersama, dan mungkin tidak pernah digunakan) setiap kali, tetapi semuanya menyetelnya dari nilai string kosong awal ke nilai string kosong baru. nilai string, membiarkannya tidak berubah.

1
torek 28 Februari 2020, 01:44