Идиоматичный способ вернуть несколько ошибок или обработать их соответственно - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть этот код, и мне не нравится, как он не упоминает, golint не нравится с error should be the last type when returning multiple items (golint).Чтобы объяснить этот код:

  • Я хочу предоставить пользователю право решать, заботятся ли они о какой-либо из возвращенных ошибок
  • В частности, в этом коде аудиофайл иногда не нуженили требуется, и его можно игнорировать
  • Видео и выходной файл, вероятно, всегда будут требоваться для всего, что делает пользователь

Я открыт для рефакторинга любым способом (будь торазбивая его на части, перемещая вещи и т. д.) Есть ли в Go более идиоматический способ достичь чего-то подобного?

// Download will download the audio and video files to a particular path
func (r *RedditVideo) Download() (outputVideoFileName string, outputAudioFileName string, errVideo error, errAudio error) {
    outputVideoFile, errVideo := downloadTemporaryFile(
        r.VideoURL,
        TemporaryVideoFilePrefix,
    )
    if errVideo == nil {
        outputVideoFileName = outputVideoFile.Name()
    }

    outputAudioFile, errAudio := downloadTemporaryFile(
        r.AudioURL,
        TemporaryAudioFilePrefix,
    )
    if errAudio == nil {
        outputAudioFileName = outputAudioFile.Name()
    }

    return outputVideoFileName, outputAudioFileName, errVideo, errAudio
}

Точно так же я обнаружил, что снова использую этот же шаблон позжев коде:

// SetFiles sets up all of the input files and the output file
func (l *localVideo) SetFiles(inputVideoFilePath string, inputAudioFilePath string, outputVideoFilePath string) (errVideo error, errAudio error, errOutputVideo error) {
	// Set input video file
	l.inputVideoFile, errVideo = os.Open(inputVideoFilePath)
	if errVideo != nil {
		return
	}
	if errVideo = l.inputVideoFile.Close(); errVideo != nil {
		return
	}

	// Set output video file
	l.outputVideoFile, errOutputVideo = os.Create(outputVideoFilePath)
	if errOutputVideo != nil {
		return
	}
	if errOutputVideo = l.outputVideoFile.Close(); errOutputVideo != nil {
		return
	}

	// IMPORTANT! Set input audio file LAST incase it is nil
	l.inputAudioFile, errAudio = os.Open(inputAudioFilePath)
	if errAudio != nil {
		return
	}
	if errAudio = l.inputAudioFile.Close(); errVideo != nil {
		return
	}

	return
}

На этот раз в этом коде снова то же самое, что и выше:

  • Мы заботимся о том, что видео и выход настроены и могутили может не заботиться об аудио
  • Существует несколько ошибок, которые нужно обработать, которые оставлены на усмотрение пользователя

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

С https://blog.golang.org/error-handling-and-go:

В коде Go используются значения ошибок для обозначения ненормального состояния.

В вашей ситуации аудио является необязательным, а видео - обязательным.Поэтому только загрузка видео должна возвращать ошибку:

// Download will download the audio and video files to a particular path
// empty outputAudioFileName indicates inability to download Audio File
func (r *RedditVideo) Download() (outputVideoFileName string, outputAudioFileName string, err error) {
    outputVideoFile, err := downloadTemporaryFile(
        r.VideoURL,
        TemporaryVideoFilePrefix,
    )
    if err != nil {
        return "", "", err 
    }
    outputVideoFileName := outputVideoFile.Name()
    outputAudioFile, errAudio := downloadTemporaryFile(
        r.AudioURL,
        TemporaryAudioFilePrefix,
    )
    outputAudioFileName := ""
    if errAudio == nil {
        outputAudioFileName = outputAudioFile.Name()
    } else {
        // Log error, it is still important to fix it
    }

    return outputVideoFileName, outputAudioFileName, nil
} 

Правило большого пальца - любой код, который может генерировать ненормальное состояние, должен иметь следующую строку:

    if err != nil {
        return funcResult, err
    }
0 голосов
/ 20 декабря 2018

В стандартной библиотеке вы можете увидеть немало специфических функций, которые оборачивают более общие неэкспортированные функции.См. Прокомментированный код ниже.

// download is a rather generic function
// and probably you can refactor downloadTemporaryFile
// so that even this function is not needed any more.
func (r *RedditVideo) download(prefix, url string) (filename string, error error) {
    outputFile, err := downloadTemporaryFile(
        r.VideoURL,
        prefix,
    )

    if err == nil {
        return "", fmt.Errorf("Error while download: %s", err)
    }

    return outputFile.Name(), nil
}

// DownloadVideo wraps download, handing over the values specific
// to the video download
func (r *RedditVideo) DownloadVideo() (filename string, averror error) {
    return r.download(TemporaryVideoFilePrefix, r.VideoURL)
}

// DownloadAudio wraps download, handing over the values specific
// to the audio download
func (r *RedditVideo) DownloadAudio() (filename string, averror error) {
    return r.download(TemporaryAudioFilePrefix, r.AudioURL)
}

func main() {

    r := RedditVideo{
        VideoURL: os.Args[1],
        AudioURL: os.Args[2],
    }

    var videoerror, audioerror error
    var videofileName, audiofileName string

    if videofileName, videoerror = r.DownloadVideo(); videoerror != nil {
        fmt.Println("Got an error downloading the video")
    }

    if audiofileName, audioerror = r.DownloadAudio(); audioerror != nil {
        fmt.Println("Got an error downloading the audio")
    }

    fmt.Printf("Video:\t%s\nAudio:\t%s", videofileName, audiofileName)
}

Таким образом, очевидно, откуда происходит загрузка возвращаемой ошибки.

...