Отказ от ответственности: я довольно новичок в Go, в частности (хотя и не в программировании ОС низкого уровня). Тем не менее, путь здесь кажется ясным.
Go как экосистема - не только самого языка, но и всех различных библиотек - пытается 1 быть переносимым. Но прямые системные вызовы в значительной степени не портативны вообще. Таким образом, здесь автоматически возникает некоторая напряженность.
Для того, чтобы сделать что-нибудь полезное, среде выполнения Go нужны различные службы из операционной системы, такие как создание потоков на уровне ОС, отправка и прием сигналов, открытие файлов и сетевых подключений и т. д. Многие из этих операций могут быть и были абстрагированы от как это делается в операционных системах A, B и от C до generi c, поддерживаемых большинством или всеми ОС . Эти абстракции основаны на фактических механизмах в различных ОС.
Они могут даже делать это внутри уровня. Например, при просмотре источника Go для пакета os
показаны исходные файлы file.go
, file_plan9.go
, file_posix.go
, file_unix.go
и file_windows.go
. В верхней части file_posix.go
показана директива +build
:
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
Очевидно, что сам этот код не полностью переносим, но подпрограммы, которые он реализует для os
, которые заключены в абстракцию os.File
, достаточно для всех POSIX-совместимых систем. Это уменьшает объем кода, который, например, должен составлять go в файле Unix / Linux -specifi c files_unix.go
.
В той степени, в которой операции уровня ОС могут быть объединены в более - абстрактные, более переносимые операции, тогда различные встроенные пакеты Go делают это. Вам не нужно знать, существует ли другой системный вызов для открытия файла устройства, например, текстового файла или двоичного файла, или длинного пути или короткого: вы просто вызываете os.Create
или os.Open
и он выполняет любую работу, необходимую за кулисами.
Эта идея не работает с системными вызовами. Системный вызов Linux для создания нового пространства имен UID не имеет эквивалента Windows. 2 A Windows WaitForMultipleObjects
Системный вызов не имеет реального эквивалента Linux. Низкоуровневые детали вызова stat / lstat отличаются от одной системы к другой и т. Д.
В ранних версиях Go была некоторая попытка описать это с помощью пакета syscall
. Но ссылка, которую вы указали - https://golang.org/s/go1.4-syscall - описывает эту попытку как если бы не удалось , по крайней мере перегрузил . Последнее слово в разделе «проблемы» - «проблемы».
В предложении по этой же ссылке сказано, что пакет syscall
должен быть заморожен (или в основном заморожен) начиная с Go 1.4: don не вводите новые функции в него. Но функций, которые имеют , достаточно для реализации новых, экспериментальных golang.org/x/sys/*
пакетов или, по крайней мере, некоторых из них. Нет ничего страшного в том, что экспериментальный пакет заимствует существующий формально устаревший пакет syscall
, если он делает то, что нужно экспериментальному новому пакету.
Вещи в golang.org/x/
экспериментальные: не стесняйтесь их использовать, но Помните, что между обновлениями версий нет обещаний совместимости, в отличие от стандартных пакетов. Итак, чтобы ответить на последнюю строчку вашего вопроса:
Почему golang/x/sys
полагается на [и поддерживает использование пакета, который он должен заменить?
Это зависит от syscall
, потому что это нормально. Это не"поощряет использование" syscall
. Просто использует , когда этого достаточно. Если по какой-либо причине этого станет недостаточно, он перестанет полагаться на него.
Отвечая на вопрос, который вы не задавали (но я сделал): предположим, вы хотите Unix -specifi c stat
информация о файле, такая как номер его индекса. У вас есть выбор:
info, err := os.Stat(path) // or os.Lstat(path), etc
if err != nil { ... handle error ... }
raw, ok := info.Sys().(*syscall.Stat_t)
if !ok { ... do whatever is appropriate ... }
inodeNumber := raw.Ino
или:
var info unix.Stat
err := unix.Stat(path, &info) // or unix.Lstat, etc
if err != nil { ... handle error ... }
inodeNumber := unix.Ino
Преимущество первого блока кода в том, что вы получаете всю другую (портативную) информацию о файле - его режим, размер и временные метки, например. Вы можете сделать, возможно, не получить номер инода; случай !ok
говорит вам, сделали ли вы. Основным недостатком здесь является то, что для этого требуется больше кода.
Преимущество второго блока кода в том, что он говорит именно то, что вы имеете в виду. Вы либо получаете всю информацию из звонка stat
, либо ничего из этого. Недостатки очевидны:
- он работает только на Unix -i sh системах, а
- использует экспериментальный пакет, поведение которого может измениться.
Так что вам решать, что из этого важнее для вас.
1 Либо это метафора, либо я просто антропоморфизировал это. Есть старое правило: не антропоморфизировать компьютеры, они ненавидят это!
2 A Linux Пространство имен UID сопоставляет UID внутри контейнера с UID вне контейнера. То есть внутри контейнера файл может принадлежать UID 1234. Если файл находится в файловой системе, которая также смонтирована вне контейнера, этот файл может принадлежать другому владельцу, возможно, 5678. Изменение владельца либо «сторона» контейнера вносит изменения в пространство имен этой стороны; изменение отображается на другой стороне в результате сопоставления или обратного сопоставления идентификатора через сопоставление пространства имен.
(Этот же прием также работает, например, для сопоставлений UID NFS. Docker Приведенный выше пример контейнера - всего лишь одно использование, но, вероятно, наиболее заметное в наши дни.)