찾다
백엔드 개발GolangGo, PostgreSQL, Google Cloud 및 CockroachDB를 사용하여 API 구축

Go와 PostgreSQL로 API를 구축하고 Google Cloud Run, Cloud Build, Secret Manager, Artifact Registry로 CI/CD 파이프라인을 설정하고 Cloud Run 인스턴스를 CockroachDB에 연결했습니다.

API는 Crisis Core: Final Fantasy VII 게임을 기반으로 "Materia Fusion"을 시뮬레이션합니다. 이 문서의 대상 독자는 API를 구축하고 배포하는 방법을 알고 싶은 개발자를 위한 것입니다. 이 프로젝트를 진행하면서 배운 모든 것, 효과가 없었던 것, 게임의 마테리아 융합 규칙을 이해하고 번역하는 것에 대해 이야기하는 또 다른 기사가 있습니다(링크는 곧 제공됩니다).

쉽게 참고할 수 있는 링크

  • GitHub 저장소 및 README
  • Swagger(OpenAPI) 문서화 및 테스트
  • 공개 우편배달부 컬렉션
  • 도메인 모델 소스

API 목표

3개의 엔드포인트 — 상태 확인(GET), 모든 물질 목록(GET), 물질 융합 시뮬레이션(POST)

도메인 모델

마테리아(단수형 및 복수형 모두)는 마법의 원천 역할을 하는 수정 구체입니다. 게임에는 144개의 서로 다른 마테리아가 있으며, 크게 "마법", "명령", "지원", "독립"의 4가지 범주로 분류됩니다. 그러나 물질 융합의 규칙을 파악하기 위해 융합 행위에 따라 32개의 내부 범주를 갖고, 해당 범주 내에 8등급을 두는 것이 더 쉬웠습니다(참고 자료 참조). .

마테리아는 일정 시간 동안 사용하면 '마스터링'됩니다. 여기서는 기간이 중요하지 않습니다.

가장 중요한 것은 2개의 마테리아를 융합하여 새로운 마테리아를 생산할 수 있다는 것입니다. 융합을 관리하는 규칙은 다음의 영향을 받습니다.

  • 마테리아 중 하나 또는 둘 다 마스터했는지 여부
  • 어떤 물질이 먼저 나오나요(X Y가 반드시 Y X와 같지는 않음).
  • 마테리아 내부 카테고리.
  • 마테리아 등급.

Building an API with Go, PostgreSQL, Google Cloud and CockroachDB

또한 예외가 많이 있으며 일부 규칙에는 3가지 수준의 중첩된 if-else 논리가 있습니다. 이렇게 하면 DB에 간단한 테이블을 만들고 그 안에 1000개의 규칙을 유지하거나 모든 것을 지배하는 하나의 공식을 만들 가능성이 제거됩니다.

요컨대 다음이 필요합니다.

  1. name(string), materia_type(ENUM)(32개의 내부 범주), grade(integer), display_materia_type(ENUM)(게임에 사용되는 4개의 범주), 설명(string) 및 id( 정수)를 자동 증가 기본 키로 사용합니다.
  2. 기본 규칙 형식 MateriaTypeA MateriaTypeB = MateriaTypeC를 캡슐화하는 데이터 구조.
  3. 기본적이고 복잡한 규칙을 사용하여 내부 카테고리 및 등급 측면에서 출력 물질을 결정하는 코드입니다.

1. 로컬 PostgreSQL DB 설정

이상적으로는 웹사이트 자체에서 DB를 설치하는 것이 좋습니다. 그런데 pgAdmin 툴이 무슨 이유인지 DB에 연결할 수 없어서 Homebrew를 사용했습니다.

설치

brew install postgresql@17

이렇게 하면 DB 사용에 도움이 되는 CLI 바이너리 파일 전체가 설치됩니다.

선택 사항: $PATH 변수에 /opt/homebrew/opt/postgresql@17/bin을 추가합니다.

# create the DB
createdb materiafusiondb
# step into the DB to perform SQL commands
psql materiafusiondb

사용자 및 권한 생성

-- create an SQL user to be used by the Go server
CREATE USER go_client WITH PASSWORD 'xxxxxxxx';

-- The Go server doesn't ever need to add data to the DB. 
-- So let's give it just read permission.
CREATE ROLE readonly_role;
GRANT USAGE ON SCHEMA public TO readonly_role;

-- This command gives SELECT access to all future created tables. 
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;

-- If you want to be more strict and give access only to tables that already exist, use this:
-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;

GRANT readonly_role TO go_client;

테이블 만들기

CREATE TYPE display_materia_type AS ENUM ('Magic', 'Command', 'Support', 'Independent');

CREATE TYPE materia_type AS ENUM ('Fire', 'Ice', 'Lightning', 'Restore', 'Full Cure', 'Status Defense', 'Defense', 'Absorb Magic', 'Status Magic', 'Fire & Status', 'Ice & Status', 'Lightning & Status', 'Gravity', 'Ultimate', 'Quick Attack', 'Quick Attack & Status', 'Blade Arts', 'Blade Arts & Status', 'Fire Blade', 'Ice Blade', 'Lightning Blade', 'Absorb Blade', 'Item', 'Punch', 'SP Turbo', 'HP Up', 'AP Up', 'ATK Up', 'VIT Up', 'MAG Up', 'SPR Up', 'Dash', 'Dualcast', 'DMW', 'Libra', 'MP Up', 'Anything');

CREATE TABLE materia (
    id integer NOT NULL,
    name character varying(50) NOT NULL,
    materia_type materia_type NOT NULL,
    grade integer NOT NULL,
    display_materia_type display_materia_type,
    description text
    CONSTRAINT materia_pkey PRIMARY KEY (id)
);

-- The primary key 'id' should auto-increment by 1 for every row entry.
CREATE SEQUENCE materia_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

ALTER SEQUENCE materia_id_seq OWNED BY materia.id;

ALTER TABLE ONLY materia ALTER COLUMN id SET DEFAULT nextval('materia_id_seq'::REGCLASS);

데이터 추가

표 헤더와 데이터가 포함된 Excel 시트를 만들고 CSV 파일로 내보냅니다. 그런 다음 다음 명령을 실행합니다.

COPY materia(name,materia_type,grade,display_materia_type,description) FROM
 '<path_to_csv_file>/materiadata.csv' DELIMITER ',' CSV HEADER;
</path_to_csv_file>

2. Go 서버 생성

autostrada.dev를 사용하여 상용구 코드를 만듭니다. api, postgresql, httprouter , env var config, Tintedlogging, git, live reload, makefile 옵션을 추가합니다. 결국 다음과 같은 파일 구조를 갖게 됩니다.

? codebase
├─ cmd
│  └─ api
│     ├─ errors.go
│     ├─ handlers.go
│     ├─ helpers.go
│     ├─ main.go
│     ├─ middleware.go
│     └─ server.go
├─ internal
│  ├─ database --- db.go
│  ├─ env --- env.go
│  ├─ request --- json.go
│  ├─ response --- json.go
│  └─ validator
│     ├─ helpers.go
│     └─ validators.go
├─ go.mod
├─ LICENSE
├─ Makefile
├─ README.md
└─ README.html

.env 파일

상용구 생성기는 환경 변수를 가져와 코드에 추가하는 코드를 생성했지만 값을 더 쉽게 추적하고 업데이트할 수 있습니다.

/.env 파일을 만듭니다. 다음 값을 추가합니다:

HTTP_PORT=4444
DB_DSN=go_client:<password>@localhost:5432/materiafusiondb?sslmode=disable
API_TIMEOUT_SECONDS=5
API_CALLS_ALLOWED_PER_SECOND=1
</password>

godotenv 라이브러리 추가:

go get github.com/joho/godotenv

main.go에 다음을 추가하세요.

// At the beginning of main():
err := godotenv.Load(".env") // Loads environment variables from .env file
if err != nil { // This will be true in prod, but that's fine.
  fmt.Println("Error loading .env file")
}


// Modify config struct:
type config struct {
  baseURL string
  db      struct {
    dsn string
  }
  httpPort                 int
  apiTimeout               int
  apiCallsAllowedPerSecond float64
}

// Modify run() to use the new values from .env:
cfg.httpPort = env.GetInt("HTTP_PORT")
cfg.db.dsn = env.GetString("DB_DSN")
cfg.apiTimeout = env.GetInt("API_TIMEOUT_SECONDS")
cfg.apiCallsAllowedPerSecond = float64(env.GetInt("API_CALLS_ALLOWED_PER_SECOND"))

// cfg.baseURL = env.GetString("BASE_URL") - not required

미들웨어 및 경로

보일러플레이트에는 패닉 상태를 복구하기 위한 미들웨어가 이미 포함되어 있습니다. 콘텐츠 유형 확인, 속도 제한, API 시간 초과 보호 등 3가지를 더 추가할 예정입니다.

톨게이트 라이브러리 추가:

go get github.com/didip/tollbooth

func (app *application) contentTypeCheck(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  if r.Header.Get("Content-Type") != "application/json" {
   app.unsupportedMediaType(w, r)

   return
  }
  next.ServeHTTP(w, r)
 })
}


func (app *application) rateLimiter(next http.Handler) http.Handler {
 limiter := tollbooth.NewLimiter(app.config.apiCallsAllowedPerSecond, nil)
 limiter.SetIPLookups([]string{"X-Real-IP", "X-Forwarded-For", "RemoteAddr"})

 return tollbooth.LimitHandler(limiter, next)
}


func (app *application) apiTimeout(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  timeoutDuration := time.Duration(app.config.apiTimeout) * time.Second

  ctx, cancel := context.WithTimeout(r.Context(), timeoutDuration)
  defer cancel()

  r = r.WithContext(ctx)

  done := make(chan struct{})

  go func() {
   next.ServeHTTP(w, r)
   close(done)
  }()

  select {
  case 



<p>경로에 미들웨어를 추가해야 합니다. 모든 경로에 추가하거나 특정 경로에 추가할 수 있습니다. 우리의 경우 Content-Type 확인(즉, 입력 헤더에 Content-Type: application/json을 포함하도록 요구)은 POST 요청에만 필요합니다. 따라서 Routes.go를 다음과 같이 수정하십시오:<br>
</p>

<pre class="brush:php;toolbar:false">func (app *application) routes() http.Handler {
 mux := httprouter.New()

 mux.NotFound = http.HandlerFunc(app.notFound)
 mux.MethodNotAllowed = http.HandlerFunc(app.methodNotAllowed)

 // Serve the Swagger UI. Uncomment this line later
 // mux.Handler("GET", "/docs/*any", httpSwagger.WrapHandler)

 mux.HandlerFunc("GET", "/status", app.status)
 mux.HandlerFunc("GET", "/materia", app.getAllMateria)

 // Adding content-type check middleware to only the POST method
 mux.Handler("POST", "/fusion", app.contentTypeCheck(http.HandlerFunc(app.fuseMateria)))

 return app.chainMiddlewares(mux)
}

func (app *application) chainMiddlewares(next http.Handler) http.Handler {
 middlewares := []func(http.Handler) http.Handler{
  app.recoverPanic,
  app.apiTimeout,
  app.rateLimiter,
 }

 for _, middleware := range middlewares {
  next = middleware(next)
 }

 return next
}

오류 처리

미들웨어 기능을 돕기 위해 /api/errors.go에 다음 메소드를 추가하세요.

func (app *application) unsupportedMediaType(w http.ResponseWriter, r *http.Request) {
 message := fmt.Sprintf("The %s Content-Type is not supported", r.Header.Get("Content-Type"))
 app.errorMessage(w, r, http.StatusUnsupportedMediaType, message, nil)
}

func (app *application) gatewayTimeout(w http.ResponseWriter, r *http.Request) {
 message := "Request timed out"
 app.errorMessage(w, r, http.StatusGatewayTimeout, message, nil)
}

요청 및 응답 구조 파일

/api/dtos.go :

package main

// MateriaDTO provides Materia details - Name, Description and Type (Magic / Command / Support / Independent)
type MateriaDTO struct {
 Name        string `json:"name" example:"Thunder"`
 Type        string `json:"type" example:"Magic"`
 Description string `json:"description" example:"Shoots lightning forward dealing thunder damage."`
}

// StatusDTO provides status of the server
type StatusDTO struct {
 Status string `json:"Status" example:"OK"`
}

// ErrorResponseDTO provides Error message
type ErrorResponseDTO struct {
 Error string `json:"Error" example:"The server encountered a problem and could not process your request"`
}

/api/requests.go :

brew install postgresql@17

생성된 코드의 유효성 검사기는 나중에 융합 엔드포인트에 대한 입력 필드의 유효성을 검사하는 데 사용됩니다.

조합 규칙의 데이터 구조

/internal/crisis-core-materia-fusion/constants.go 파일을 생성합니다

다음을 추가하세요.

# create the DB
createdb materiafusiondb
# step into the DB to perform SQL commands
psql materiafusiondb

여기에서 32개의 MateriaType의 전체 목록을 확인할 수 있습니다.

/internal/crisis-core-materia-fusion/models.go 파일을 생성합니다

다음을 추가하세요.

-- create an SQL user to be used by the Go server
CREATE USER go_client WITH PASSWORD 'xxxxxxxx';

-- The Go server doesn't ever need to add data to the DB. 
-- So let's give it just read permission.
CREATE ROLE readonly_role;
GRANT USAGE ON SCHEMA public TO readonly_role;

-- This command gives SELECT access to all future created tables. 
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;

-- If you want to be more strict and give access only to tables that already exist, use this:
-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;

GRANT readonly_role TO go_client;

여기에서 전체 규칙 목록을 확인할 수 있습니다.

api/handlers.go의 물질 처리기

CREATE TYPE display_materia_type AS ENUM ('Magic', 'Command', 'Support', 'Independent');

CREATE TYPE materia_type AS ENUM ('Fire', 'Ice', 'Lightning', 'Restore', 'Full Cure', 'Status Defense', 'Defense', 'Absorb Magic', 'Status Magic', 'Fire & Status', 'Ice & Status', 'Lightning & Status', 'Gravity', 'Ultimate', 'Quick Attack', 'Quick Attack & Status', 'Blade Arts', 'Blade Arts & Status', 'Fire Blade', 'Ice Blade', 'Lightning Blade', 'Absorb Blade', 'Item', 'Punch', 'SP Turbo', 'HP Up', 'AP Up', 'ATK Up', 'VIT Up', 'MAG Up', 'SPR Up', 'Dash', 'Dualcast', 'DMW', 'Libra', 'MP Up', 'Anything');

CREATE TABLE materia (
    id integer NOT NULL,
    name character varying(50) NOT NULL,
    materia_type materia_type NOT NULL,
    grade integer NOT NULL,
    display_materia_type display_materia_type,
    description text
    CONSTRAINT materia_pkey PRIMARY KEY (id)
);

-- The primary key 'id' should auto-increment by 1 for every row entry.
CREATE SEQUENCE materia_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

ALTER SEQUENCE materia_id_seq OWNED BY materia.id;

ALTER TABLE ONLY materia ALTER COLUMN id SET DEFAULT nextval('materia_id_seq'::REGCLASS);

서버 내 캐시

다음과 같은 이유로 서버 내 캐시를 사용하고 있습니다.

  1. DB에서 가져온 데이터는 절대 변경되지 않습니다.
  2. 마테리아 엔드포인트와 융합 엔드포인트 모두 동일한 데이터를 사용합니다.

main.go 업데이트:

COPY materia(name,materia_type,grade,display_materia_type,description) FROM
 '<path_to_csv_file>/materiadata.csv' DELIMITER ',' CSV HEADER;
</path_to_csv_file>

api/helpers.go 업데이트:

? codebase
├─ cmd
│  └─ api
│     ├─ errors.go
│     ├─ handlers.go
│     ├─ helpers.go
│     ├─ main.go
│     ├─ middleware.go
│     └─ server.go
├─ internal
│  ├─ database --- db.go
│  ├─ env --- env.go
│  ├─ request --- json.go
│  ├─ response --- json.go
│  └─ validator
│     ├─ helpers.go
│     └─ validators.go
├─ go.mod
├─ LICENSE
├─ Makefile
├─ README.md
└─ README.html

api/handlers.go의 융합을 위한 핸들러

HTTP_PORT=4444
DB_DSN=go_client:<password>@localhost:5432/materiafusiondb?sslmode=disable
API_TIMEOUT_SECONDS=5
API_CALLS_ALLOWED_PER_SECOND=1
</password>

전체 핸들러 코드는 여기에서 찾을 수 있습니다.

Swagger UI 및 OpenAPI 정의 문서

Swagger 라이브러리 추가:

go get github.com/joho/godotenv

routes.go에서 Swagger 줄의 주석 처리를 제거하고 import를 추가합니다.

// At the beginning of main():
err := godotenv.Load(".env") // Loads environment variables from .env file
if err != nil { // This will be true in prod, but that's fine.
  fmt.Println("Error loading .env file")
}


// Modify config struct:
type config struct {
  baseURL string
  db      struct {
    dsn string
  }
  httpPort                 int
  apiTimeout               int
  apiCallsAllowedPerSecond float64
}

// Modify run() to use the new values from .env:
cfg.httpPort = env.GetInt("HTTP_PORT")
cfg.db.dsn = env.GetString("DB_DSN")
cfg.apiTimeout = env.GetInt("API_TIMEOUT_SECONDS")
cfg.apiCallsAllowedPerSecond = float64(env.GetInt("API_CALLS_ALLOWED_PER_SECOND"))

// cfg.baseURL = env.GetString("BASE_URL") - not required

핸들러, DTO 및 모델 파일에서 Swagger 문서에 대한 설명을 추가합니다. 모든 옵션에 대해서는 이것을 참조하세요.

터미널에서 다음을 실행하세요.

go get github.com/didip/tollbooth

이렇게 하면 Go, JSON 및 YAML에 사용할 수 있는 정의가 포함된 api/docs 폴더가 생성됩니다.

테스트하려면 로컬 서버를 시작하고 http://localhost:4444/docs를 엽니다.


최종 폴더 구조:

func (app *application) contentTypeCheck(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  if r.Header.Get("Content-Type") != "application/json" {
   app.unsupportedMediaType(w, r)

   return
  }
  next.ServeHTTP(w, r)
 })
}


func (app *application) rateLimiter(next http.Handler) http.Handler {
 limiter := tollbooth.NewLimiter(app.config.apiCallsAllowedPerSecond, nil)
 limiter.SetIPLookups([]string{"X-Real-IP", "X-Forwarded-For", "RemoteAddr"})

 return tollbooth.LimitHandler(limiter, next)
}


func (app *application) apiTimeout(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  timeoutDuration := time.Duration(app.config.apiTimeout) * time.Second

  ctx, cancel := context.WithTimeout(r.Context(), timeoutDuration)
  defer cancel()

  r = r.WithContext(ctx)

  done := make(chan struct{})

  go func() {
   next.ServeHTTP(w, r)
   close(done)
  }()

  select {
  case 



<h2>
  
  
  3. CockroachDB에서 원격 PostgreSQL 인스턴스 설정
</h2>

<ol>
<li>여기의 단계를 따르세요.</li>
<li>인증서 생성 후 프로젝트에 <rootfolder>/certs/root.crt를 생성하고 여기에 인증서를 추가합니다. 나중에 Google Run 구성에서 이 파일을 참조할 것입니다.</rootfolder>
</li>
<li>
<strong>주의!</strong> 이 폴더를 원격 저장소로 푸시하지 <strong>않습니다</strong>. .gitignore에 certs/ 폴더를 추가합니다. 원하는 경우 연결을 테스트하기 위해서만 로컬에서 인증서를 생성하고 있습니다.</li>
<li>이제 CockroachDB → 대시보드 → 왼쪽 메뉴 → 데이터베이스로 이동하면 생성한 DB를 확인할 수 있습니다.</li>
</ol>

<h3>
  
  
  이주
</h3>

<p>로컬 DB 인스턴스에서 다음을 실행합니다.<br>
</p><pre class="brush:php;toolbar:false">brew install postgresql@17
  1. CockroachDB → 왼쪽 메뉴 → 마이그레이션 → 스키마 추가 → 방금 받은 SQL 파일을 드래그하세요. 테이블 데이터 삽입을 제외한 모든 단계가 실행됩니다. 또한 실행된 단계 목록도 표시됩니다.
  2. 이 기사를 작성할 당시 CockroachDB의 PostgreSQL 인스턴스는 IMPORT INTO와 같은 문을 지원하지 않습니다. 그래서 로컬 SQL 파일에 270개 행에 대한 INSERT 문을 생성해야 했습니다(방금 얻은 pg_dump 출력에서 ​​파생할 수 있음).
  3. 원격 인스턴스에 로그인하여 SQL 파일을 실행하세요.

원격 인스턴스에 로그인:

# create the DB
createdb materiafusiondb
# step into the DB to perform SQL commands
psql materiafusiondb

4. Google Cloud Run 인스턴스 배포

  1. 이와 같은 Dockerfile을 생성하세요.
  2. Google Cloud Run으로 이동하여 API용 새 프로젝트를 생성하세요.
  3. 서비스 생성 → 저장소에서 지속적으로 배포클라우드 빌드로 설정저장소 제공자 = Github → 저장소 선택 → 빌드 유형 = Dockerfile → 저장.
  4. 인증 = 인증되지 않은 호출을 허용.
  5. 대부분의 기본값은 그대로 유지하면 됩니다.
  6. 컨테이너까지 아래로 스크롤 → 컨테이너 포트 = 4444.
  7. 변수 및 비밀 탭을 선택하고 로컬 .env 파일에 있는 것과 동일한 환경 변수를 추가합니다.

값:

  1. HTTP_PORT = 4444
  2. DB_DSN = ?sslmode=verify-full&sslrootcert=/app/certs/root.crt
  3. API_TIMEOUT_SECONDS = 5
  4. API_CALLS_ALLOWED_PER_SECOND = 1

인증서에 Google Secret Manager 사용

퍼즐의 마지막 조각.

  1. Secret Manager 검색 → Secret 생성 → 이름 = 'DB_CERT' → CockroachDB의 .crt 인증서를 업로드하세요.
  2. Cloud Run → (귀하의 서비스) → 지속 배포 편집 클릭 → 구성까지 아래로 스크롤 → 편집기 열기
  3. 첫 번째 단계로 다음을 추가하세요.
-- create an SQL user to be used by the Go server
CREATE USER go_client WITH PASSWORD 'xxxxxxxx';

-- The Go server doesn't ever need to add data to the DB. 
-- So let's give it just read permission.
CREATE ROLE readonly_role;
GRANT USAGE ON SCHEMA public TO readonly_role;

-- This command gives SELECT access to all future created tables. 
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;

-- If you want to be more strict and give access only to tables that already exist, use this:
-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;

GRANT readonly_role TO go_client;

이렇게 하면 Cloud Build가 빌드가 시작되기 전에 프로젝트에 certs/root.crt 파일을 생성하므로 Dockerfile은 Github 저장소에 푸시하지 않은 경우에도 해당 파일에 액세스할 수 있습니다.


그리고 그게 다입니다. 커밋을 푸시하고 빌드가 트리거되는지 확인하세요. Cloud Run 대시보드에는 호스팅된 Go 서버의 URL이 표시됩니다.


“왜 Y를 하지 않고 X를 하였나요?” 관련 질문 읽어보세요.

알고 싶은 내용이나 토론하고 싶은 내용이 있으면 여기로 이동하거나 아래에 댓글을 남겨주세요.

위 내용은 Go, PostgreSQL, Google Cloud 및 CockroachDB를 사용하여 API 구축의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
Golang : Go 프로그래밍 언어가 설명되었습니다Golang : Go 프로그래밍 언어가 설명되었습니다Apr 10, 2025 am 11:18 AM

GO의 핵심 기능에는 쓰레기 수집, 정적 연결 및 동시성 지원이 포함됩니다. 1. Go Language의 동시성 모델은 고루틴 및 채널을 통한 효율적인 동시 프로그래밍을 실현합니다. 2. 인터페이스 및 다형성은 인터페이스 방법을 통해 구현되므로 서로 다른 유형을 통일 된 방식으로 처리 할 수 ​​있습니다. 3. 기본 사용법은 기능 정의 및 호출의 효율성을 보여줍니다. 4. 고급 사용에서 슬라이스는 동적 크기 조정의 강력한 기능을 제공합니다. 5. 레이스 조건과 같은 일반적인 오류는 Getest-race를 통해 감지 및 해결할 수 있습니다. 6. 성능 최적화는 sync.pool을 통해 개체를 재사용하여 쓰레기 수집 압력을 줄입니다.

Golang의 목적 : 효율적이고 확장 가능한 시스템 구축Golang의 목적 : 효율적이고 확장 가능한 시스템 구축Apr 09, 2025 pm 05:17 PM

Go Language는 효율적이고 확장 가능한 시스템을 구축하는 데 잘 작동합니다. 장점은 다음과 같습니다. 1. 고성능 : 기계 코드로 컴파일, 빠른 달리기 속도; 2. 동시 프로그래밍 : 고어 라틴 및 채널을 통한 멀티 태스킹 단순화; 3. 단순성 : 간결한 구문, 학습 및 유지 보수 비용 절감; 4. 크로스 플랫폼 : 크로스 플랫폼 컴파일, 쉬운 배포를 지원합니다.

SQL 분류의 진술에 의한 순서 결과가 때때로 무작위로 보이는 이유는 무엇입니까?SQL 분류의 진술에 의한 순서 결과가 때때로 무작위로 보이는 이유는 무엇입니까?Apr 02, 2025 pm 05:24 PM

SQL 쿼리 결과의 정렬에 대해 혼란스러워합니다. SQL을 학습하는 과정에서 종종 혼란스러운 문제가 발생합니다. 최근 저자는 "Mick-SQL 기본 사항"을 읽고 있습니다.

기술 스택 컨버전스는 기술 스택 선택의 프로세스 일뿐입니까?기술 스택 컨버전스는 기술 스택 선택의 프로세스 일뿐입니까?Apr 02, 2025 pm 05:21 PM

기술 스택 컨버전스와 기술 선택의 관계, 소프트웨어 개발에서 기술 스택의 선택 및 관리는 매우 중요한 문제입니다. 최근에 일부 독자들은 ...

반사 비교를 사용하고 GO의 세 구조의 차이점을 처리하는 방법은 무엇입니까?반사 비교를 사용하고 GO의 세 구조의 차이점을 처리하는 방법은 무엇입니까?Apr 02, 2025 pm 05:15 PM

GO 언어로 세 가지 구조를 비교하고 처리하는 방법. GO 프로그래밍에서는 때때로 두 구조의 차이점을 비교하고 이러한 차이점을 ...에 적용해야합니다.

GO에서 전 세계적으로 설치된 패키지를 보는 방법?GO에서 전 세계적으로 설치된 패키지를 보는 방법?Apr 02, 2025 pm 05:12 PM

GO에서 전 세계적으로 설치된 패키지를 보는 방법? Go Language로 발전하는 과정에서 Go는 종종 사용합니다 ...

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까?골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까?Apr 02, 2025 pm 05:09 PM

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? Go Language 개발을 위해 Goland를 사용할 때 많은 개발자가 사용자 정의 구조 태그를 만날 것입니다 ...

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

MinGW - Windows용 미니멀리스트 GNU

MinGW - Windows용 미니멀리스트 GNU

이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구