Ранний возврат
Есть вот такая функция, которая проверяет разрешения пользователя.
// CanEdit returns true if the user can edit objects.
func CanEdit(user *User) bool {
if user.IsActive() {
perms := user.Permissions()
for _, perm := range perms {
if perm == PermWrite {
return true
}
}
return false
} else {
return false
}
}
Я спросил на канале, что люди о ней думают. Вот результаты опроса:
Что думаете о функции?
4% Да это ж круто!
■
42% Сомнительно, но окэй
■■■■■■■■
46% Это конечно печально
■■■■■■■■■
8% Вот мне лично это не интересно
■■
Что ж, давайте разбираться.
Оставим за скобками вопросики к типу User
— например, почему CanEdit
не сделан методом. Для простоты будем считать, что тип User
менять нельзя.
Первая проблема — нет проверки на nil. Вторая — отсутствие early return (он же guard clause). С nil, думаю, и так понятно, а вот на раннем возврате остановимся подробнее.
В реальной жизни проверки в функциях часто бывают более сложными, вроде таких:
func Do() {
if cond_1 {
// do stuff
if cond_2 {
// do more stuff
if cond_3 {
// do even more stuff
}
}
}
}
Читать такое больно из-за лесенки ифов. Лучше переделать на ранний возврат, а «основной сценарий» сделать без отступов:
func Do() {
if !cond_1 {
return
}
// do stuff
if !cond_2 {
return
}
// do more stuff
if !cond_3 {
return
}
// do even more stuff
}
Теперь явно видно, что делает функция, и что в ней может пойти не так.
Применим к CanEdit
:
func CanEdit(user *User) bool {
if user == nil || !user.IsActive() {
return false
}
for _, perm := range user.Permissions() {
if perm == PermRead {
return true
}
}
return false
}
Можно еще заменить цикл на slices.Contains
(хотя это уже частности):
func CanEdit(user *User) bool {
if user == nil || !user.IsActive() {
return false
}
perms := user.Permissions()
return slices.Contains(perms, PermRead)
}
Главное — не забывайте проверять на nil и использовать ранний возврат.
★ Подписывайтесь на новые заметки.