Я должен поместить много функций в один файл? Или, более или менее, одна функция на файл?

В Go напишите простую функцию. Например,

package main

import (
    "fmt"
)

func isStandard(s string) bool {
    for i := 0; i < len(s); i++ {
        switch b := s[i]; {
        case b >= 'a' && b <= 'z':
            continue
        case b >= 'A' && b <= 'Z':
            continue
        case b >= '0' && b <= '9':
            continue
        default:
            return false
        }
    }
    return true
}

func main() {
    fmt.Println(isStandard(`ABCabc123`))
    fmt.Println(isStandard(`#}{&*"(£)`))
}

Детская площадка: https://play.golang.org/p/Y2KjDcHSupH

Вывод:

true
false

Спецификация языка программирования Go

Операторы Switch

Операторы «Switch» обеспечивают многофакторное выполнение. Спецификатор выражения или типа сравнивается с «падежами» внутри «переключателя», чтобы определить, какую ветвь выполнять.

Переключатели выражений

В переключателе выражений вычисляется выражение переключателя, а выражения регистра, которые не должны быть константами, оцениваются слева направо и сверху вниз; первое, равное выражению переключателя, запускает выполнение операторов соответствующего случая; другие дела пропущены. Если ни один регистр не соответствует и существует регистр «по умолчанию», выполняются его операторы. Может быть не более одного случая по умолчанию, и он может появляться где угодно в операторе «switch».

Выражению-переключателю может предшествовать простое выражение, которое выполняется до того, как выражение будет оценено.

Операторы Fallthrough

Оператор «fallthrough» передает управление первому оператору следующего предложения case в выражении «switch». Он может использоваться только как последнее непустое утверждение в таком предложении.

blockquote>
switch b := s[i]; {
    // ...
}

эквивалентно

switch b := s[i]; true {
    // ...
}

эквивалентно

{
    b := s[i]
    switch true {
        // ...
    } 
}

Простое утверждение b := s[i] объявляет b как switch { } Локальная переменная блока операторов.

Выражения случая оцениваются и сравниваются с true. Если ни один из них не соответствует действительности, берется default.

Go, в отличие от C, требует явного fallthrough.

ASCII является подмножеством Unicode UTF-8. Поскольку все стандартные символы являются ASCII, мы можем просто сравнить байты.


Вот простой тест.

Вывод:

$ go test standard_test.go -bench=. -benchmem
BenchmarkPeterSO-8    200000000       8.10 ns/op    0 B/op    0 allocs/op
BenchmarkJubobs-8      10000000     222 ns/op       0 B/op    0 allocs/op
$ 

standard_test.go:

package main

import (
    "regexp"
    "testing"
)

func isStandard(s string) bool {
    for i := 0; i < len(s); i++ {
        switch b := s[i]; {
        case b >= 'a' && b <= 'z':
            continue
        case b >= 'A' && b <= 'Z':
            continue
        case b >= '0' && b <= '9':
            continue
        default:
            return false
        }
    }
    return true
}

func BenchmarkPeterSO(b *testing.B) {
    std := `ABCabc123`
    for N := 0; N < b.N; N++ {
        isStandard(std)
    }
}

var (
    whitelist  = "A-Za-z0-9"
    disallowed = regexp.MustCompile("[^" + whitelist + " ]+")
)

func IsValid(s string) bool {
    return !disallowed.MatchString(s)
}

func BenchmarkJubobs(b *testing.B) {
    std := `ABCabc123`
    for N := 0; N < b.N; N++ {
        IsValid(std)
    }
}

10
задан Frank 10 February 2009 в 05:46
поделиться

8 ответов

По моему скромному мнению, необходимо объединить объекты в логические группировки и создать файлы на основе этого.

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

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

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

9
ответ дан 3 December 2019 в 15:36
поделиться

Мы используем принцип одной внешней функции на файл. Однако в этом файле может быть несколько других функций "помощника" в пространствах имен без имени, которые используются для реализации той функции.

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

// getShapeColor.h
Color getShapeColor(Shape);

// getTextColor.h
Color getTextColor(Text);

Я не соглашаюсь, что стандартная библиотека является хорошим примером для того, чтобы не использовать одну (внешнюю) функцию на файл. Стандартные библиотеки никогда не изменяют и имеют четко определенные интерфейсы и таким образом, ни одна из точек выше не относится к ним.

Однако даже в случае стандартной библиотеки существуют некоторые потенциальные выгоды в разделении отдельных функций. Прежде всего, компиляторы могли генерировать полезное предупреждение, когда небезопасные версии функций используются, например, strcpy по сравнению с strncpy, похожим способом к тому, как g ++ раньше предупреждал для включения <iostream.h> по сравнению с <iostream>.

Другое преимущество состоит в том, что я больше не ловился бы включением памяти, когда я хочу использовать memmove!

4
ответ дан 3 December 2019 в 15:36
поделиться

Одна функция на файл могла стать грязной, по-моему. Вообразите, были ли POSIX и ANSI C заголовки сделаны тем же путем.

#include <strlen.h>
#include <strcpy.h>
#include <strncpy.h>
#include <strchr.h>
#include <strstr.h>
#include <malloc.h>
#include <calloc.h>
#include <free.h>
#include <printf.h>
#include <fprintf.h>
#include <vpritnf.h>
#include <snprintf.h>

Один класс на файл является хорошей идеей все же.

8
ответ дан 3 December 2019 в 15:36
поделиться

Можно повторно объявить некоторые функции, как являющиеся статическими методами одного или нескольких классов: это дает Вам возможность (и хорошее оправдание) для группировки нескольких из них в единственный исходный файл.

Одно серьезное основание для того, чтобы иметь или не иметь несколько функций в исходных файлах, если тот исходный файл является непосредственным с объектными файлами и компоновщиком, связывает все объектные файлы: если исполняемый файл мог бы хотеть одну функцию, но не другого, то помещенный их в отдельные исходные файлы (так, чтобы компоновщик мог связаться один без другого).

1
ответ дан 3 December 2019 в 15:36
поделиться

Старый преподаватель программирования мое предложенное разбивание модулей каждые несколько сотен строк кода для пригодности для обслуживания. Я больше не разрабатываю в C++, но в C# я ограничиваю меня одним классом на файл, и размер файла не имеет значения, пока нет ничего несвязанного с моим объектом. Можно использовать #pragma регионы для корректного сокращения пространства редактора, не уверенного, если компилятор C++ имеет их, но если это действительно затем определенно использует их.

Если бы я все еще программировал в C++, то я сгруппировал бы функции использованием с помощью нескольких функций на файл. Таким образом, у меня может быть файл под названием 'Service.cpp' с несколькими функциями, которые определяют тот "сервис". Наличие одной функции на файл в свою очередь заставит сожаление находить свой путь назад в Ваш проект так или иначе, некоторым образом.

Наличие нескольких тысяч строк кода на файл не необходимо часть времени все же. Сами функции никогда не должны быть намного больше чем несколькими сотнями строк кода самое большее. Всегда помните, что функция должна только сделать одну вещь и быть сохранена минимальной. Если функция делает больше чем одну вещь, она должна быть пересмотрена во вспомогательные методы.

Никогда не повреждает иметь несколько исходных файлов, которые определяют единственный объект также. Т.е.: 'ServiceConnection.cpp' 'ServiceSettings.cpp', и так далее так дальше.

Иногда, если я делаю отдельный объект, и он владеет другими объектами, я объединю несколько классов в единственный файл. Например, кнопочное управление, которое содержит объекты 'ButtonLink', я мог бы объединить это в класс Кнопки. Иногда я не делаю, но это - "предпочтение момента" решение.

Сделайте что работы лучше всего для Вас. Эксперимент немного с различными стилями на меньших проектах может помочь. Надежда это выручает Вас немного.

1
ответ дан 3 December 2019 в 15:36
поделиться

Для части заголовка необходимо объединить объекты в логические группировки и создать заголовочные файлы на основе этого. Это кажется и очень логично, по моему скромному мнению.

Для исходной части необходимо поместить каждую реализацию функции в отдельный исходный файл (статические функции являются исключениями в этом случае). Это не может казаться логичным сначала, но помнить, компилятор знает о функциях, но компоновщик знает только о.o и .obj файлах и его экспортируемых символах. Это может изменить размер выходного файла значительно, и это - очень важная проблема для встроенных систем.

Контроль glibc или Visual C++ исходное дерево CRT...

1
ответ дан 3 December 2019 в 15:36
поделиться

Я также пытался разделить файлы в функции на файл, но он имел некоторые недостатки. Иногда функции имеют тенденцию становиться больше, чем им нужно к (Вы не хотите добавлять новый.c файл каждый раз), если Вы не прилежны о рефакторинге Вашего кода (я не).

В настоящее время я помещал одну - три функции в.c файл и группу все.c файлы для функциональности в каталоге. Для заголовочных файлов я имею Funcionality.h и Subfunctionality.h так, чтобы я мог включать все функции сразу при необходимости или просто маленькую служебную функцию, если целый пакет не нужен.

1
ответ дан 3 December 2019 в 15:36
поделиться

Я вижу некоторые преимущества для Вашего подхода, но существует несколько недостатков:

  1. Включая пакет кошмар. Можно закончить с 10-20, включает для получения функций, в которых Вы нуждаетесь. Например, вообразите, были ли STDIO или StdLib реализованы этот путь.

  2. Просмотр кода будет небольшим количеством боли, так как в целом легче просмотреть файл путем прокрутки, чем переключить файлы. Очевидно слишком большой из файла твердо, но даже там с современными IDE довольно легко свернуть файл вниз к тому, в чем Вы нуждаетесь, и у большого количества из них есть функциональные списки короткого пути.

  3. Обслуживание make-файла является болью.

  4. Я - огромный поклонник небольших функций и рефакторинга. Когда Вы добавляете наверху (делающий новый файл, добавляя его к управлению исходным кодом...) это поощряет людей писать более длительные функции, где вместо того, чтобы повредить одну функцию в три части, Вы просто делаете одну большую.

1
ответ дан 3 December 2019 в 15:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: