


Menguji REST API dalam Go: Panduan untuk Ujian Unit dan Penyepaduan dengan Perpustakaan Ujian Standard Go
Nov 17, 2024 am 01:33 AMpengenalan
Artikel ini akan membawa anda melalui cara menggunakan ujian unit dan ujian integrasi untuk meningkatkan pengalaman pembangunan anda semasa anda membuat apis rehat di golang.
Ujian unit direka bentuk untuk mengesahkan kefungsian bahagian terkecil, bahagian individu aplikasi, selalunya memfokuskan pada satu fungsi atau kaedah. Ujian ini dijalankan secara berasingan daripada bahagian lain kod untuk memastikan setiap komponen berfungsi seperti yang diharapkan dengan sendirinya.
Ujian integrasi, sebaliknya, menilai cara modul atau komponen aplikasi yang berbeza berfungsi bersama. Dalam artikel ini, kami akan menumpukan pada ujian penyepaduan untuk aplikasi Go kami, khususnya menyemak sama ada ia berinteraksi dengan betul dengan pangkalan data PostgreSQL dengan berjaya membuat dan melaksanakan pertanyaan SQL.
Artikel ini menganggap bahawa anda sudah biasa dengan golang dan cara membuat api rehat dalam golang tumpuan utama adalah untuk mencipta ujian untuk laluan anda (ujian unit) dan menguji fungsi pertanyaan sql anda (ujian integrasi) untuk rujukan, lawati github untuk melihat projek itu.
Menyediakan
Dengan mengandaikan anda telah menyediakan projek anda serupa dengan yang dipautkan di atas, anda akan mempunyai struktur folder yang serupa dengan ini
test_project |__cmd |__api |__api.go |__main.go |__db |___seed.go |__internal |___db |___db.go |___services |___records |___routes_test.go |___routes.go |___store_test.go |___store.go |___user |___routes_test.go |___routes.go |___store_test.go |___store.go |__test_data |__docker-compose.yml |__Dockerfile |__Makefile
Pengujian dalam golang mudah dibandingkan dengan bahasa lain yang mungkin anda temui kerana pakej ujian terbina yang menyediakan alatan yang diperlukan untuk menulis ujian.
Fail ujian dinamakan dengan _test.go akhiran ini membenarkan go untuk menyasarkan fail ini untuk dilaksanakan semasa menjalankan ujian arahan go.
Titik masuk untuk projek kami ialah fail main.go yang terletak dalam folder cmd
// main.go package main import ( "log" "finance-crud-app/cmd/api" "finance-crud-app/internal/db" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) type Server struct { db *sqlx.DB mux *mux.Router } func NewServer(db *sqlx.DB, mux *mux.Router) *Server { return &Server{ db: db, mux: mux, } } func main() { connStr := "postgres://postgres:Password123@localhost:5432/crud_db?sslmode=disable" dbconn, err := db.NewPGStorage(connStr) if err != nil { log.Fatal(err) } defer dbconn.Close() server := api.NewAPIServer(":8085", dbconn) if err := server.Run(); err != nil { log.Fatal(err) } }
Daripada kod anda boleh lihat kami sedang mencipta pelayan api baharu dengan menghantar sambungan pangkalan data dan nombor port. Selepas mencipta pelayan, kami menjalankannya pada port yang dinyatakan.
Arahan NewAPIServer datang daripada fail api.go yang
// api.go package api import ( "finance-crud-app/internal/services/records" "finance-crud-app/internal/services/user" "log" "net/http" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" ) type APIServer struct { addr string db *sqlx.DB } func NewAPIServer(addr string, db *sqlx.DB) *APIServer { return &APIServer{ addr: addr, db: db, } } func (s *APIServer) Run() error { router := mux.NewRouter() subrouter := router.PathPrefix("/api/v1").Subrouter() userStore := user.NewStore(s.db) userHandler := user.NewHandler(userStore) userHandler.RegisterRoutes(subrouter) recordsStore := records.NewStore(s.db) recordsHandler := records.NewHandler(recordsStore, userStore) recordsHandler.RegisterRoutes(subrouter) log.Println("Listening on", s.addr) return http.ListenAndServe(s.addr, router) }
Untuk api ini kami menggunakan mux sebagai penghala http kami.
Ujian Integrasi
Kami mempunyai struktur Kedai pengguna yang mengendalikan pertanyaan sql yang berkaitan dengan entiti pengguna.
// store.go package user import ( "errors" "finance-crud-app/internal/types" "fmt" "log" "github.com/jmoiron/sqlx" ) var ( CreateUserError = errors.New("cannot create user") RetrieveUserError = errors.New("cannot retrieve user") DeleteUserError = errors.New("cannot delete user") ) type Store struct { db *sqlx.DB } func NewStore(db *sqlx.DB) *Store { return &Store{db: db} } func (s *Store) CreateUser(user types.User) (user_id int, err error) { query := ` INSERT INTO users (firstName, lastName, email, password) VALUES (, , , ) RETURNING id` var userId int err = s.db.QueryRow(query, user.FirstName, user.LastName, user.Email, user.Password).Scan(&userId) if err != nil { return -1, CreateUserError } return userId, nil } func (s *Store) GetUserByEmail(email string) (types.User, error) { var user types.User err := s.db.Get(&user, "SELECT * FROM users WHERE email = ", email) if err != nil { return types.User{}, RetrieveUserError } if user.ID == 0 { log.Fatalf("user not found") return types.User{}, RetrieveUserError } return user, nil } func (s *Store) GetUserByID(id int) (*types.User, error) { var user types.User err := s.db.Get(&user, "SELECT * FROM users WHERE id = ", id) if err != nil { return nil, RetrieveUserError } if user.ID == 0 { return nil, fmt.Errorf("user not found") } return &user, nil } func (s *Store) DeleteUser(email string) error { user, err := s.GetUserByEmail(email) if err != nil { return DeleteUserError } // delete user records first _, err = s.db.Exec("DELETE FROM records WHERE userid = ", user.ID) if err != nil { return DeleteUserError } _, err = s.db.Exec("DELETE FROM users WHERE email = ", email) if err != nil { return DeleteUserError } return nil }
Dalam fail di atas kami mempunyai 3 kaedah penerima penunjuk:
- CreateUser
- GetUserByEmail
- GetUserById
Untuk kaedah ini untuk melaksanakan fungsi mereka, mereka perlu berinteraksi dengan sistem luaran yang , dalam kes ini iaitu Postgres DB .
Untuk menguji kaedah ini, kami akan membuat fail store_test.go dahulu. Dalam go, kami biasanya menamakan fail ujian kami selepas fail yang kami sasarkan untuk menguji dan menambah akhiran _test.go .
// store_test.go package user_test import ( "finance-crud-app/internal/db" "finance-crud-app/internal/services/user" "finance-crud-app/internal/types" "log" "os" "testing" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) var ( userTestStore *user.Store testDB *sqlx.DB ) func TestMain(m *testing.M) { // database ConnStr := "postgres://postgres:Password123@localhost:5432/crud_db?sslmode=disable" testDB, err := db.NewPGStorage(ConnStr) if err != nil { log.Fatalf("could not connect %v", err) } defer testDB.Close() userTestStore = user.NewStore(testDB) code := m.Run() os.Exit(code) } func TestCreateUser(t *testing.T) { test_data := map[string]struct { user types.User result any }{ "should PASS valid user email used": { user: types.User{ FirstName: "testfirsjjlkjt-1", LastName: "testlastkjh-1", Email: "validuser@email.com", Password: "00000000", }, result: nil, }, "should FAIL invalid user email used": { user: types.User{ FirstName: "testFirstName1", LastName: "testLastName1", Email: "test1@email.com", Password: "800890", }, result: user.CreateUserError, }, } for name, tc := range test_data { t.Run(name, func(t *testing.T) { value, got := userTestStore.CreateUser(tc.user) if got != tc.result { t.Errorf("test fail expected %v got %v instead and value %v", tc.result, got, value) } }) } t.Cleanup(func() { err := userTestStore.DeleteUser("validuser@email.com") if err != nil { t.Errorf("could not delete user %v got error %v", "validuser@email.com", err) } }) } func TestGetUserByEmail(t *testing.T) { test_data := map[string]struct { email string result any }{ "should pass valid user email address used": { email: "test1@email.com", result: nil, }, "should fail invalid user email address used": { email: "validuser@email.com", result: user.RetrieveUserError, }, } for name, tc := range test_data { got, err := userTestStore.GetUserByEmail(tc.email) if err != tc.result { t.Errorf("test fail expected %v instead got %v", name, got) } } } func TestGetUserById(t *testing.T) { testUserId, err := userTestStore.CreateUser(types.User{ FirstName: "userbyid", LastName: "userbylast", Email: "unique_email", Password: "unique_password", }) if err != nil { log.Panicf("got %v when creating testuser", testUserId) } test_data := map[string]struct { user_id int result any }{ "should pass valid user id used": { user_id: testUserId, result: nil, }, "should fail invalid user id used": { user_id: 0, result: user.RetrieveUserError, }, } for name, tc := range test_data { t.Run(name, func(t *testing.T) { _, got := userTestStore.GetUserByID(tc.user_id) if got != tc.result { t.Errorf("error retrieving user by id got %v want %v", got, tc.result) } }) } t.Cleanup(func() { err := userTestStore.DeleteUser("unique_email") if err != nil { t.Errorf("could not delete user %v got error %v", "unique_email", err) } }) } func TestDeleteUser(t *testing.T) { testUserId, err := userTestStore.CreateUser(types.User{ FirstName: "userbyid", LastName: "userbylast", Email: "delete_user@email.com", Password: "unique_password", }) if err != nil { log.Panicf("got %v when creating testuser", testUserId) } test_data := map[string]struct { user_email string result error }{ "should pass user email address used": { user_email: "delete_user@email.com", result: nil, }, } for name, tc := range test_data { t.Run(name, func(t *testing.T) { err = userTestStore.DeleteUser(tc.user_email) if err != tc.result { t.Errorf("error deletig user got %v instead of %v", err, tc.result) } }) } t.Cleanup(func() { err := userTestStore.DeleteUser("delete_user@email.com") if err != nil { log.Printf("could not delete user %v got error %v", "delete_user@email.com", err) } }) }
Mari lihat fail melihat apa yang dilakukan oleh setiap bahagian.
Tindakan pertama ialah mengisytiharkan pembolehubah userTestStore dan testDB. Pembolehubah ini akan digunakan untuk menyimpan penunjuk ke stor pengguna dan db masing-masing. Sebab kami mengisytiharkannya dalam skop fail global adalah kerana kami mahu semua fungsi dalam fail ujian mempunyai akses kepada penunjuk.
Fungsi TestMain membolehkan kami melakukan beberapa tindakan persediaan sebelum ujian utama dijalankan. Kami pada mulanya menyambung ke kedai postgres dan menyimpan penunjuk ke dalam pembolehubah global kami.
Kami telah menggunakan penunjuk itu untuk mencipta userTestStore yang akan kami gunakan untuk melaksanakan pertanyaan sql yang kami cuba sambungkan.
tunda testDB.Close() menutup sambungan pangkalan data selepas ujian selesai
kod := m.Run() menjalankan seluruh fungsi ujian sebelum kembali dan keluar.
FungsiTestCreateUser akan mengendalikan ujian fungsi create_user. Matlamat kami adalah untuk menguji sama ada fungsi itu akan mencipta pengguna jika e-mel unik diluluskan dan fungsi itu sepatutnya tidak boleh mencipta pengguna jika e-mel bukan unik telah digunakan untuk mencipta pengguna lain.
Mula-mula kami mencipta data ujian yang akan kami gunakan untuk menguji kedua-dua senario kes.
test_project |__cmd |__api |__api.go |__main.go |__db |___seed.go |__internal |___db |___db.go |___services |___records |___routes_test.go |___routes.go |___store_test.go |___store.go |___user |___routes_test.go |___routes.go |___store_test.go |___store.go |__test_data |__docker-compose.yml |__Dockerfile |__Makefile
Saya akan mengulangi peta yang melaksanakan fungsi create_user dengan tarikh ujian sebagai parameter dan bandingkan jika nilai yang dikembalikan adalah sama dengan hasil yang kami jangkakan
// main.go package main import ( "log" "finance-crud-app/cmd/api" "finance-crud-app/internal/db" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) type Server struct { db *sqlx.DB mux *mux.Router } func NewServer(db *sqlx.DB, mux *mux.Router) *Server { return &Server{ db: db, mux: mux, } } func main() { connStr := "postgres://postgres:Password123@localhost:5432/crud_db?sslmode=disable" dbconn, err := db.NewPGStorage(connStr) if err != nil { log.Fatal(err) } defer dbconn.Close() server := api.NewAPIServer(":8085", dbconn) if err := server.Run(); err != nil { log.Fatal(err) } }
Untuk kes di mana keputusan yang dikembalikan tidak sama dengan keputusan yang dijangkakan maka ujian kami akan gagal
Bahagian terakhir fungsi ini menggunakan fungsi pakej ujian terbina dalam Pembersihan. Fungsi ini mendaftarkan fungsi yang akan dipanggil apabila semua fungsi dalam ujian telah dilaksanakan. Dalam kes contoh kami di sini, kami menggunakan fungsi untuk mengosongkan data pengguna yang digunakan semasa pelaksanaan fungsi ujian ini.
Ujian Unit
Untuk ujian unit kami, kami akan menguji pengendali laluan untuk api kami. Dalam kes ini laluan yang berkaitan dengan entiti pengguna. Perhatikan di bawah.
// api.go package api import ( "finance-crud-app/internal/services/records" "finance-crud-app/internal/services/user" "log" "net/http" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" ) type APIServer struct { addr string db *sqlx.DB } func NewAPIServer(addr string, db *sqlx.DB) *APIServer { return &APIServer{ addr: addr, db: db, } } func (s *APIServer) Run() error { router := mux.NewRouter() subrouter := router.PathPrefix("/api/v1").Subrouter() userStore := user.NewStore(s.db) userHandler := user.NewHandler(userStore) userHandler.RegisterRoutes(subrouter) recordsStore := records.NewStore(s.db) recordsHandler := records.NewHandler(recordsStore, userStore) recordsHandler.RegisterRoutes(subrouter) log.Println("Listening on", s.addr) return http.ListenAndServe(s.addr, router) }
Kami mempunyai 3 fungsi di sini yang ingin kami uji
- HandleLogin
- Daftar Pengendali
- HandleGetUser
HandleGetUser
Fungsi handleGetUser dalam pengendali ini mendapatkan semula butiran pengguna berdasarkan ID pengguna yang disediakan dalam URL permintaan HTTP. Ia bermula dengan mengekstrak userID daripada pembolehubah laluan permintaan menggunakan penghala mux. Jika ID pengguna tiada atau tidak sah (bukan integer), ia bertindak balas dengan ralat 400 Permintaan Buruk. Setelah disahkan, fungsi memanggil kaedah GetUserByID pada stor data untuk mendapatkan maklumat pengguna. Jika ralat berlaku semasa mendapatkan semula, ia mengembalikan Ralat Pelayan Dalaman 500. Apabila berjaya, ia bertindak balas dengan status 200 OK, menghantar butiran pengguna sebagai JSON dalam badan respons.
Seperti yang dinyatakan sebelum ini untuk anda menguji fungsi pengendali yang kami perlukan untuk mencipta routes_test.go. Lihat saya di bawah
test_project |__cmd |__api |__api.go |__main.go |__db |___seed.go |__internal |___db |___db.go |___services |___records |___routes_test.go |___routes.go |___store_test.go |___store.go |___user |___routes_test.go |___routes.go |___store_test.go |___store.go |__test_data |__docker-compose.yml |__Dockerfile |__Makefile
Fungsi Pengendali Baharu kami memerlukan stor pengguna sebagai parameter untuknya mencipta struct pengendali.
Oleh kerana kita tidak memerlukan stor sebenar, kita mencipta struct olok-olok dan mencipta fungsi penerima yang mengejek fungsi struct sebenar. Kami melakukan ini kerana kami mengendalikan ujian fungsi kedai secara berasingan oleh itu kami tidak perlu menguji bahagian kod itu dalam ujian pengendali.
Fungsi ujian TestGetUserHandler menguji dua senario kes, yang pertama cuba mendapatkan pengguna tanpa memberikan id pengguna
// main.go package main import ( "log" "finance-crud-app/cmd/api" "finance-crud-app/internal/db" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) type Server struct { db *sqlx.DB mux *mux.Router } func NewServer(db *sqlx.DB, mux *mux.Router) *Server { return &Server{ db: db, mux: mux, } } func main() { connStr := "postgres://postgres:Password123@localhost:5432/crud_db?sslmode=disable" dbconn, err := db.NewPGStorage(connStr) if err != nil { log.Fatal(err) } defer dbconn.Close() server := api.NewAPIServer(":8085", dbconn) if err := server.Run(); err != nil { log.Fatal(err) } }
Ujian dijangka lulus jika permintaan http membalas dengan 400 kod status.
Senario kes ujian kedua ialah kes di mana kami mendapatkan semula maklumat pengguna dengan menggunakan url yang betul yang mengandungi id pengguna yang sah. Dalam kes ujian ini kami menjangkakan respons dengan 200 kod status. Jika tidak ujian itu akan gagal.
// api.go package api import ( "finance-crud-app/internal/services/records" "finance-crud-app/internal/services/user" "log" "net/http" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" ) type APIServer struct { addr string db *sqlx.DB } func NewAPIServer(addr string, db *sqlx.DB) *APIServer { return &APIServer{ addr: addr, db: db, } } func (s *APIServer) Run() error { router := mux.NewRouter() subrouter := router.PathPrefix("/api/v1").Subrouter() userStore := user.NewStore(s.db) userHandler := user.NewHandler(userStore) userHandler.RegisterRoutes(subrouter) recordsStore := records.NewStore(s.db) recordsHandler := records.NewHandler(recordsStore, userStore) recordsHandler.RegisterRoutes(subrouter) log.Println("Listening on", s.addr) return http.ListenAndServe(s.addr, router) }
Kesimpulan
Kami telah berjaya melaksanakan ujian unit dalam projek kami dengan mencipta ujian untuk pengendali laluan kami. Kami telah melihat cara menggunakan olok-olok untuk hanya menguji unit kecil kod. Kami telah dapat membangunkan ujian integrasi untuk fungsi kami yang berinteraksi dengan Postgresql DB.
Jika anda mahukan sedikit masa dengan kod projek klon repo dari github di sini
Atas ialah kandungan terperinci Menguji REST API dalam Go: Panduan untuk Ujian Unit dan Penyepaduan dengan Perpustakaan Ujian Standard Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Pergi menyusun program ke dalam binari mandiri secara lalai, sebab utama adalah menghubungkan statik. 1. Penyebaran yang lebih mudah: Tiada pemasangan tambahan perpustakaan ketergantungan, boleh dijalankan secara langsung di seluruh pengagihan Linux; 2. Saiz binari yang lebih besar: termasuk semua kebergantungan menyebabkan saiz fail meningkat, tetapi boleh dioptimumkan melalui bendera bangunan atau alat pemampatan; 3. Predikabiliti dan keselamatan yang lebih tinggi: Elakkan risiko yang dibawa oleh perubahan dalam versi perpustakaan luaran dan meningkatkan kestabilan; 4. Fleksibiliti operasi terhad: Tidak boleh kemas kini panas perpustakaan yang dikongsi, dan penyusunan semula dan penggunaan diperlukan untuk memperbaiki kelemahan ketergantungan. Ciri-ciri ini sesuai untuk alat CLI, microservices dan senario lain, tetapi perdagangan diperlukan dalam persekitaran di mana penyimpanan dihadkan atau bergantung kepada pengurusan berpusat.

Goensuresmemorysafetywithoutmanualmanagementthroughautomaticgarbagecollection,nopointerarithmetic,safeconcurrency,andruntimechecks.First,Go’sgarbagecollectorautomaticallyreclaimsunusedmemory,preventingleaksanddanglingpointers.Second,itdisallowspointe

Untuk membuat saluran penampan di Go, hanya tentukan parameter kapasiti dalam fungsi membuat. Saluran Buffer membolehkan operasi penghantaran untuk menyimpan data sementara apabila tiada penerima, selagi kapasiti yang ditentukan tidak melebihi. Sebagai contoh, Ch: = Make (Chanint, 10) mencipta saluran penampan yang boleh menyimpan sehingga 10 nilai integer; Tidak seperti saluran yang tidak dibuang, data tidak akan disekat dengan segera apabila menghantar, tetapi data akan disimpan sementara dalam penampan sehingga ia diambil oleh penerima; Apabila menggunakannya, sila ambil perhatian: 1. Tetapan kapasiti harus munasabah untuk mengelakkan sisa memori atau penyekatan kerap; 2. Penimbal perlu mencegah masalah ingatan daripada terkumpul selama -lamanya dalam penampan; 3. Isyarat boleh diluluskan oleh jenis Chanstruct {} untuk menjimatkan sumber; Senario biasa termasuk mengawal bilangan konkurensi, model pengguna dan pembezaan

GO sangat sesuai untuk pengaturcaraan sistem kerana ia menggabungkan prestasi bahasa yang disusun seperti C dengan kemudahan penggunaan dan keselamatan bahasa moden. 1. Dari segi operasi fail dan direktori, pakej OS Go menyokong penciptaan, penghapusan, penamaan semula dan memeriksa sama ada fail dan direktori wujud. Gunakan OS.READFILE untuk membaca keseluruhan fail dalam satu baris kod, yang sesuai untuk menulis skrip sandaran atau alat pemprosesan log; 2. Dari segi pengurusan proses, fungsi exec.command pakej OS/EXEC boleh melaksanakan arahan luaran, menangkap output, menetapkan pembolehubah persekitaran, aliran input dan output mengalihkan, dan kitaran hayat proses kawalan, yang sesuai untuk alat automasi dan skrip penempatan; 3. Dari segi rangkaian dan kesesuaian, pakej bersih menyokong pengaturcaraan TCP/UDP, pertanyaan DNS dan set asal.

Dalam bahasa Go, memanggil kaedah struktur memerlukan terlebih dahulu menentukan struktur dan kaedah yang mengikat penerima, dan mengaksesnya menggunakan nombor titik. Selepas menentukan segi empat tepat struktur, kaedah boleh diisytiharkan melalui penerima nilai atau penerima penunjuk; 1. Gunakan penerima nilai seperti kawasan func (rrectangle) int dan terus memanggilnya melalui rect.area (); 2. Jika anda perlu mengubah suai struktur, gunakan penerima penunjuk seperti func (R*segi empat) setWidth (...), dan GO akan secara automatik mengendalikan penukaran penunjuk dan nilai; 3. Apabila membenamkan struktur, kaedah struktur tertanam akan diperbaiki, dan ia boleh dipanggil secara langsung melalui struktur luar; 4. Pergi tidak perlu memaksa menggunakan getter/setter,

Di GO, antara muka adalah jenis yang mentakrifkan tingkah laku tanpa menentukan pelaksanaan. Antara muka terdiri daripada tandatangan kaedah, dan mana -mana jenis yang melaksanakan kaedah ini secara automatik memenuhi antara muka. Sebagai contoh, jika anda menentukan antara muka penceramah yang mengandungi kaedah bercakap (), semua jenis yang melaksanakan kaedah boleh dipertimbangkan pembesar suara. Antara muka sesuai untuk menulis fungsi umum, butiran pelaksanaan abstrak, dan menggunakan objek mengejek dalam ujian. Menentukan antara muka menggunakan kata kunci antara muka dan menyenaraikan tandatangan kaedah, tanpa secara jelas mengisytiharkan jenis untuk melaksanakan antara muka. Kes penggunaan biasa termasuk log, pemformatan, abstraksi pangkalan data atau perkhidmatan yang berbeza, dan sistem pemberitahuan. Sebagai contoh, kedua -dua jenis anjing dan robot boleh melaksanakan kaedah bercakap dan menyampaikannya kepada anno yang sama

Dalam bahasa Go, operasi rentetan terutamanya dilaksanakan melalui pakej rentetan dan fungsi terbina dalam. 1.Strings.Contains () digunakan untuk menentukan sama ada rentetan mengandungi substring dan mengembalikan nilai boolean; 2.Strings.index () boleh mencari lokasi di mana substring muncul untuk kali pertama, dan jika ia tidak wujud, ia kembali -1; 3.Strings.ReplaceAll () boleh menggantikan semua substrings yang sepadan, dan juga boleh mengawal bilangan pengganti melalui string.replace (); 4. Len () Fungsi digunakan untuk mendapatkan panjang bait rentetan, tetapi apabila memproses Unicode, anda perlu memberi perhatian kepada perbezaan antara aksara dan bait. Fungsi ini sering digunakan dalam senario seperti penapisan data, parsing teks, dan pemprosesan rentetan.

TheGoioPackageProvidesInderFacesLikeReaderAndWritertohandlei/ooperatiationUniformlyAsssources.1.io.Reader'sReadmethodenablesreadingingfromvarioussourcessuchasfilesorhtpresponses.2.WriterSwriteShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileShacileS.
