主頁 > 後端開發 > ent orm筆記4---Code Generation

ent orm筆記4---Code Generation

2020-09-10 01:36:12 後端開發

在前面幾篇文章中,我們經常使用的可能就是entc這個命令了,entc這個工具給帶來了很多功能,這篇文章主要整理關于ent orm 中Code Generation

之前的例子中有個知識點少整理了,就是關于如果我們想要看orm在執行程序中詳細原生sql陳述句是可以開啟Debug看到的,代碼如下:

client, err := ent.Open("mysql", "root:123456@tcp(10.211.55.3:3306)/graph_traversal?parseTime=True",ent.Debug())

序言

Initialize A New Schema

通過類似如下命令可以生成Schema 模板:

entc init User Pet

init 將在ent/schema 目錄下創建兩個schema user.go 和 pet.go ,如果ent目錄不存在,則會創建

Generate Assets

在添加了fields 和 edges 后,可以在專案的根目錄運行entc generate 或者使用go generate 生成代碼

go generate ./ent

Generate 命令生成以下內容:

  • 用于與graph 互動的Client 和Tx物件
  • schema 的CRUD生成器
  • 每個schema型別的Entity物件
  • 用于與構建互動的常量和斷言
  • SQL方言的migrate 包

Version Compatibility Between entc And ent

這里主要是關于在專案中使用ent 的時候ent的版本要和entc的包的版本相同,并且專案中使用Go modules 進行包管理

Code Generation Options

要了解更多關于 codegen 選項的資訊,entc generate -h :

generate go code for the schema directory

Usage:
  entc generate [flags] path

Examples:
  entc generate ./ent/schema
  entc generate github.com/a8m/x

Flags:
      --header string                           override codegen header
  -h, --help                                    help for generate
      --idtype [int int64 uint uint64 string]   type of the id field (default int)
      --storage string                          storage driver to support in codegen (default "sql")
      --target string                           target directory for codegen
      --template strings                        external templates to execute

Storage

entc 可以為 SQL 和 Gremlin 方言生成資產,

External Templates

接受要執行的外部 Go 模板,如果模板名稱已經由 entc 定義,它將覆寫現有的名稱,否則,它將把執行輸出寫入與模板同名的檔案,Flag 格式支持如下檔案、目錄和 glob:

entc generate --template <dir-path> --template glob="path/to/*.tmpl" ./ent/schema

更多的資訊和例子可以在外部模板檔案中找到

Use entc As A Package

運行 entc 的另一個選項是將其作為一個包使用,如下所示:

package main

import (
    "log"

    "github.com/facebook/ent/entc"
    "github.com/facebook/ent/entc/gen"
    "github.com/facebook/ent/schema/field"
)

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Header: "// Your Custom Header",
        IDType: &field.TypeInfo{Type: field.TypeInt},
    })
    if err != nil {
        log.Fatal("running ent codegen:", err)
    }
}

Schema Description

如果想要得到我們定義的schema的描述資訊,可以通過如下命令:

entc describe ./ent/schema

以之前的例子中執行效果如下:

User:
        +-------+--------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
        | Field |  Type  | Unique | Optional | Nillable | Default | UpdateDefault | Immutable |       StructTag       | Validators |
        +-------+--------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
        | id    | <nil>  | false  | false    | false    | false   | false         | false     | json:"id,omitempty"   |          0 |
        | name  | string | false  | false    | false    | false   | false         | false     | json:"name,omitempty" |          0 |
        +-------+--------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
        +-----------+------+---------+-----------+----------+--------+----------+
        |   Edge    | Type | Inverse |  BackRef  | Relation | Unique | Optional |
        +-----------+------+---------+-----------+----------+--------+----------+
        | followers | User | true    | following | M2M      | false  | true     |
        | following | User | false   |           | M2M      | false  | true     |
        +-----------+------+---------+-----------+----------+--------+----------+

CRUD API

Create A New Client

MySQL

package main

import (
    "log"

    "<project>/ent"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    client, err := ent.Open("mysql", "<user>:<pass>@tcp(<host>:<port>)/<database>?parseTime=True")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}

PostgreSQL

package main

import (
    "log"

    "<project>/ent"

    _ "github.com/lib/pq"
)

func main() {
    client, err := ent.Open("postgres","host=<host> port=<port> user=<user> dbname=<database> password=<pass>")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}

SQLite

package main

import (
    "log"

    "<project>/ent"

    _ "github.com/mattn/go-sqlite3"
)

func main() {
    client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}

Gremlin (AWS Neptune)

package main

import (
    "log"

    "<project>/ent"
)

func main() {
    client, err := ent.Open("gremlin", "http://localhost:8182")
    if err != nil {
        log.Fatal(err)
    }
}

Create An Entity

Save a user.

a8m, err := client.User.    // UserClient.
    Create().               // User create builder.
    SetName("a8m").         // Set field value.
    SetNillableAge(age).    // Avoid nil checks.
    AddGroups(g1, g2).      // Add many edges.
    SetSpouse(nati).        // Set unique edge.
    Save(ctx)               // Create and return.

SaveX a pet; Unlike Save, SaveX panics if an error occurs.

pedro := client.Pet.    // PetClient.
    Create().           // Pet create builder.
    SetName("pedro").   // Set field value.
    SetOwner(a8m).      // Set owner (unique edge).
    SaveX(ctx)          // Create and return.

Create Many

Save a bulk of pets

names := []string{"pedro", "xabi", "layla"}
bulk := make([]*ent.PetCreate, len(names))
for i, name := range names {
    bulk[i] = client.Pet.Create().SetName(name).SetOwner(a8m)
}
pets, err := client.Pet.CreateBulk(bulk...).Save(ctx)

Update One

更新一個從資料庫回傳的entity

a8m, err = a8m.Update().    // User update builder.
    RemoveGroup(g2).        // Remove specific edge.
    ClearCard().            // Clear unique edge.
    SetAge(30).             // Set field value
    Save(ctx)               // Save and return.

Update By ID

pedro, err := client.Pet.   // PetClient.
    UpdateOneID(id).        // Pet update builder.
    SetName("pedro").       // Set field name.
    SetOwnerID(owner).      // Set unique edge, using id.
    Save(ctx)               // Save and return.

Update Many

以斷言進行過濾

n, err := client.User.          // UserClient.
    Update().                   // Pet update builder.
    Where(                      //
        user.Or(                // (age >= 30 OR name = "bar") 
            user.AgeEQ(30),     //
            user.Name("bar"),   // AND
        ),                      //  
        user.HasFollowers(),    // UserHasFollowers()  
    ).                          //
    SetName("foo").             // Set field name.
    Save(ctx)                   // exec and return.

通過edge 斷言進行查詢

n, err := client.User.          // UserClient.
    Update().                   // Pet update builder.
    Where(                      // 
        user.HasFriendsWith(    // UserHasFriendsWith (
            user.Or(            //   age = 20
                user.Age(20),   //      OR
                user.Age(30),   //   age = 30
            )                   // )
        ),                      //
    ).                          //
    SetName("a8m").             // Set field name.
    Save(ctx)                   // exec and return.

Query The Graph

獲取所有用戶的關注者

users, err := client.User.      // UserClient.
    Query().                    // User query builder.
    Where(user.HasFollowers()). // filter only users with followers.
    All(ctx)                    // query and return.

獲取特定用戶的所有跟隨者; 從graph中的一個節點開始遍歷

users, err := a8m.
    QueryFollowers().
    All(ctx)

獲取所有寵物的名字

names, err := client.Pet.
    Query().
    Select(pet.FieldName).
    Strings(ctx)

獲取所有寵物的名字和年齡

var v []struct {
    Age  int    `json:"age"`
    Name string `json:"name"`
}
err := client.Pet.
    Query().
    Select(pet.FieldAge, pet.FieldName).
    Scan(ctx, &v)
if err != nil {
    log.Fatal(err)
}

Delete One

這個用于如果我們已經通過client查詢到了一個entity,然后想要洗掉這條記錄:

err := client.User.
    DeleteOne(a8m).
    Exec(ctx)

Delete by ID.

err := client.User.
    DeleteOneID(id).
    Exec(ctx)

Delete Many

使用斷言進行洗掉

err := client.File.
    Delete().
    Where(file.UpdatedAtLT(date))
    Exec(ctx)

Mutation

通過 entc init 生成的每個schema 都有自己的mutaion,例如我們通過 entc init User Pet, 在通過go generate ./ent 生成的代碼中有 ent/mutation.go

在該檔案中定義了:

.....
// UserMutation represents an operation that mutate the Users
// nodes in the graph.
type UserMutation struct {
	config
	op            Op
	typ           string
	id            *int
	name          *string
	age           *int
	addage        *int
	clearedFields map[string]struct{}
	done          bool
	oldValue      func(context.Context) (*User, error)
}

.....

// PetMutation represents an operation that mutate the Pets
// nodes in the graph.
type PetMutation struct {
	config
	op            Op
	typ           string
	id            *int
	name          *string
	age           *int
	addage        *int
	clearedFields map[string]struct{}
	done          bool
	oldValue      func(context.Context) (*Pet, error)
}

例如,所有的User builders都共享相同的UserMutaion 物件,左右的builder 型別都繼承通用的ent.Mutation介面.

這里所說的 user builders,拿User schema來說指的是UserCreateUserDeleteUserQueryUserUpdate 物件,go generate 生成的代碼中,我們可以到

./ent/user_create.go、./ent/user_delete.go、./ent/user_query.go、./ent/user_update.go檔案中看到如下定義:

// ./ent/user_create.go

// UserCreate is the builder for creating a User entity.
type UserCreate struct {
	config
	mutation *UserMutation
	hooks    []Hook
}


//./ent/user_delete.go
// UserDelete is the builder for deleting a User entity.
type UserDelete struct {
	config
	hooks      []Hook
	mutation   *UserMutation
	predicates []predicate.User
}

// ./ent/user_query.go
// UserQuery is the builder for querying User entities.
type UserQuery struct {
	config
	limit      *int
	offset     *int
	order      []OrderFunc
	unique     []string
	predicates []predicate.User
	// intermediate query (i.e. traversal path).
	sql  *sql.Selector
	path func(context.Context) (*sql.Selector, error)
}

// ./ent/user_update.go
// UserUpdate is the builder for updating User entities.
type UserUpdate struct {
	config
	hooks      []Hook
	mutation   *UserMutation
	predicates []predicate.User
}

在下面的例子中,ent.UserCreate 和 ent.UserUpdate 都使用一個通用的方法對age 和name 列進行操作:

package main

import (
   "context"
   "log"

   _ "github.com/go-sql-driver/mysql"
   "github.com/peanut-cc/ent_orm_notes/aboutMutaion/ent"
)

func main() {
   client, err := ent.Open("mysql", "root:123456@tcp(10.211.55.3:3306)/aboutMutaion?parseTime=True")
   if err != nil {
      log.Fatal(err)
   }
   defer client.Close()
   ctx := context.Background()
   // run the auto migration tool
   if err := client.Schema.Create(ctx); err != nil {
      log.Fatalf("failed creating schema resources:%v", err)
   }
   Do(ctx, client)
}

func Do(ctx context.Context, client *ent.Client) {
   creator := client.User.Create()
   SetAgeName(creator.Mutation())
   creator.SaveX(ctx)
   updater := client.User.UpdateOneID(1)
   SetAgeName(updater.Mutation())
   updater.SaveX(ctx)
}

// SetAgeName sets the age and the name for any mutation.
func SetAgeName(m *ent.UserMutation) {
   m.SetAge(32)
   m.SetName("Ariel")
}

在某些情況下,你希望對多個不同的型別應用同一個方法,對于這種情況,要么使用通用的ent.Mutation 介面,或者自己實作一個介面,代碼如下:

func Do2(ctx context.Context, client *ent.Client) {
   creator1 := client.User.Create().SetAge(18)
   SetName(creator1.Mutation(), "a8m")
   creator1.SaveX(ctx)
   creator2 := client.Pet.Create().SetAge(16)
   SetName(creator2.Mutation(), "pedro")
   creator2.SaveX(ctx)
}

// SetNamer wraps the 2 methods for getting
// and setting the "name" field in mutations.
type SetNamer interface {
   SetName(string)
   Name() (string, bool)
}

func SetName(m SetNamer, name string) {
   if _, exist := m.Name(); !exist {
      m.SetName(name)
   }
}

Graph Traversal

在這個部分的例子中會使用如下的Graph

er-traversal-graph

er-traversal-graph-gopher

上面的遍歷從一個 Group 物體開始,繼續到它的 admin (edge) ,繼續到它的朋友(edge) ,獲取他們的寵物(edge) ,獲取每個寵物的朋友(edge) ,并請求它們的主人

func Traverse(ctx context.Context, client *ent.Client) error {
    owner, err := client.Group.         // GroupClient.
        Query().                        // Query builder.
        Where(group.Name("Github")).    // Filter only Github group (only 1).
        QueryAdmin().                   // Getting Dan.
        QueryFriends().                 // Getting Dan's friends: [Ariel].
        QueryPets().                    // Their pets: [Pedro, Xabi].
        QueryFriends().                 // Pedro's friends: [Coco], Xabi's friends: [].
        QueryOwner().                   // Coco's owner: Alex.
        Only(ctx)                       // Expect only one entity to return in the query.
    if err != nil {
        return fmt.Errorf("failed querying the owner: %v", err)
    }
    fmt.Println(owner)
    // Output:
    // User(id=3, age=37, name=Alex)
    return nil
}

下面的遍歷如何?

er-traversal-graph-gopher-query

我們希望得到所有寵物(entities)的所有者(edge)是朋友(edge)的一些群管理員(edge),

func Traverse2(ctx context.Context, client *ent.Client) error {
	pets, err := client.Pet.
		Query().
		Where(
			pet.HasOwnerWith(
				user.HasFriendsWith(
					user.HasManage(),
				),
			),
		).
		All(ctx)
	if err != nil {
		return fmt.Errorf("failed querying the pets: %v", err)
	}
	fmt.Println(pets)
	// Output:
	// [Pet(id=1, name=Pedro) Pet(id=2, name=Xabi)]
	return nil
}

上面的查詢中,查詢所有的寵物,條件是: 寵物要有主人,同時寵物的主人是要有朋友,同時該主人還要屬于管理員

Eager Loading

ent 支持通過它們的edges 查詢,并將關聯的entities 添加到回傳的物件中

通過下面的例子理解:

er-group-users

查詢上面關系中所有用戶和它們的寵物,代碼如下:

func edgerLoading(ctx context.Context, client *ent.Client) {
   users, err := client.User.Query().WithPets().All(ctx)
   if err != nil {
      log.Fatalf("user query failed:%v", err)
   }
   log.Println(users)
   for _, u := range users {
      for _, p := range u.Edges.Pets {
         log.Printf("user (%v) -- > Pet (%v)\n", u.Name, p.Name)
      }
   }

}

完整的代碼在:https://github.com/peanut-cc/ent_orm_notes/graph_traversal

查詢的結果如下:

2020/09/01 20:09:07 [User(id=1, age=29, name=Dan) User(id=2, age=30, name=Ariel) User(id=3, age=37, name=Alex) User(id=4, age=18, name=peanut)]
2020/09/01 20:09:07 user (Ariel) -- > Pet (Pedro)
2020/09/01 20:09:07 user (Ariel) -- > Pet (Xabi)
2020/09/01 20:09:07 user (Alex) -- > Pet (Coco)

預加載允許查詢多個關聯,包括嵌套關聯,還可以過濾,排序或限制查詢結果,例如:

func edgerLoading2(ctx context.Context, client *ent.Client) {
   users, err := client.User.
      Query().
      Where(
         user.AgeGT(18),
      ).
      WithPets().
      WithGroups(func(q *ent.GroupQuery) {
         q.Limit(5)
         q.WithUsers().Limit(5)
      }).All(ctx)
   if err != nil {
      log.Fatalf("user query failed:%v", err)
   }
   log.Println(users)
   for _, u := range users {
      for _, p := range u.Edges.Pets {
         log.Printf("user (%v) --> Pet (%v)\n", u.Name, p.Name)
      }
      for _, g := range u.Edges.Groups {
         log.Printf("user (%v) -- Group (%v)\n", u.Name, g.Name)
      }
   }

}

每個query-builder都有一個方法串列,其形式為 With<E>(...func(<N>Query))

<E>代表邊緣名稱(像WithGroups) ,< N> 代表邊緣型別(像GroupQuery),

注意,只有 SQL 方言支持這個特性

Aggregation

Group By

按所有用戶的姓名和年齡欄位分組,并計算其總年齡,

package main

import (
	"context"
	"log"

	"github.com/peanut-cc/ent_orm_notes/groupBy/ent/user"

	_ "github.com/go-sql-driver/mysql"

	"github.com/peanut-cc/ent_orm_notes/groupBy/ent"
)

func main() {
	client, err := ent.Open("mysql", "root:123456@tcp(10.211.55.3:3306)/groupBy?parseTime=True",
		ent.Debug())
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()
	ctx := context.Background()
	// run the auto migration tool
	if err := client.Schema.Create(ctx); err != nil {
		log.Fatalf("failed creating schema resources:%v", err)
	}
	GenData(ctx, client)
	Do(ctx, client)

}

func GenData(ctx context.Context, client *ent.Client) {
	client.User.Create().SetName("peanut").SetAge(18).SaveX(ctx)
	client.User.Create().SetName("jack").SetAge(20).SaveX(ctx)
	client.User.Create().SetName("steve").SetAge(22).SaveX(ctx)
	client.User.Create().SetName("peanut-cc").SetAge(18).SaveX(ctx)
	client.User.Create().SetName("jack-dd").SetAge(18).SaveX(ctx)
}

func Do(ctx context.Context, client *ent.Client) {
	var v []struct {
		Name  string `json:"name"`
		Age   int    `json:"age"`
		Sum   int    `json:"sum"`
		Count int    `json:"count"`
	}
	client.User.
		Query().
		GroupBy(
			user.FieldName, user.FieldAge,
		).
		Aggregate(
			ent.Count(),
			ent.Sum(user.FieldAge),
		).
		ScanX(ctx, &v)
	log.Println(v)

}

按一個欄位分組,例子如下:

func Do2(ctx context.Context, client *ent.Client) {
	names := client.User.Query().GroupBy(user.FieldName).StringsX(ctx)
	log.Println(names)
}

Predicates

Field Predicates

  • Bool:
    • =, !=
  • Numberic:
    • =, !=, >, <, >=, <=,
    • IN, NOT IN
  • Time:
    • =, !=, >, <, >=, <=
    • IN, NOT IN
  • String:
    • =, !=, >, <, >=, <=
    • IN, NOT IN
    • Contains, HasPrefix, HasSuffix
    • ContainsFold, EqualFold (SQL specific)
  • Optional fields:
    • IsNil, NotNil

Edge Predicates

HasEdge 例如,查詢所有寵物的所有者,使用:

 client.Pet.
      Query().
      Where(pet.HasOwner()).
      All(ctx)

HasEdgeWith

 client.Pet.
      Query().
      Where(pet.HasOwnerWith(user.Name("a8m"))).
      All(ctx)

Negation (NOT)

client.Pet.
    Query().
    Where(pet.Not(pet.NameHasPrefix("Ari"))).
    All(ctx)

Disjunction (OR)

client.Pet.
    Query().
    Where(
        pet.Or(
            pet.HasOwner(),
            pet.Not(pet.HasFriends()),
        )
    ).
    All(ctx)

Conjunction (AND)

client.Pet.
    Query().
    Where(
        pet.And(
            pet.HasOwner(),
            pet.Not(pet.HasFriends()),
        )
    ).
    All(ctx)

Custom Predicates

如果想撰寫自己的特定于方言的邏輯,Custom predicates可能很有用,

pets := client.Pet.
    Query().
    Where(predicate.Pet(func(s *sql.Selector) {
        s.Where(sql.InInts(pet.OwnerColumn, 1, 2, 3))
    })).
    AllX(ctx)

Paging And Ordering

Limit

將查詢結果限制為 n 個物體,

users, err := client.User.
    Query().
    Limit(n).
    All(ctx)

Offset

設定從查詢回傳的第一個最大數量,

users, err := client.User.
    Query().
    Offset(10).
    All(ctx)

Ordering

Order 回傳按一個或多個欄位的值排序的物體,

users, err := client.User.Query().
    Order(ent.Asc(user.FieldName)).
    All(ctx)

延伸閱讀

  • https://entgo.io/

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/334.html

標籤:Go

上一篇:【Go語言入門系列】(八)Go語言是不是面向物件語言?

下一篇:[Go]GO語言實戰專案-在線WEB客服GO-FLY即時通訊管理系統架構

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more