與 AI 同行。
出題
最直接使用 AI 的方法,就是出題。出題方式適用於寫工具類。
如 “再談函數式編程:釋放編程創造力” 一文所示。
再給一例:
AI + 函數式 + 泛型編程,將能讓你的編程效率成倍提升。
package util
import (
"runtime"
"sync"
)
/*
* 接收一個普通函數 plainFunc,返回一個可以併發調用 plainFunc 的函數,這個函數接收一個列表,返回另一個列表
* 這個結果列表由單個函數調用結果彙集而成
*/
func ConcurrentExecute[T any, R any](plainFunc func([]T) []R) func([]T) []R {
return func(list []T) []R {
ch := make(chan []R)
var wg sync.WaitGroup
subListSize := len(list) / runtime.NumCPU()
if subListSize == 0 {
subListSize = 1
}
for i := 0; i < len(list); i += subListSize {
end := i + subListSize
if end > len(list) {
end = len(list)
}
wg.Add(1)
go func(start, end int) {
defer wg.Done()
ch <- plainFunc(list[start:end])
}(i, end)
}
go func() {
wg.Wait()
close(ch)
}()
var finalResult []R
for resultPart := range ch {
finalResult = append(finalResult, resultPart...)
}
return finalResult
}
}
利用 AI 生成自動化工具
更復雜的出題,讓 AI 生成自動化的完整實用工具。注意要詳述要求。
比如,java 工程轉 Go,需要把大量 Java 對象轉成 Go 結構體。需要一個批量轉換工具,不是手工編碼。
寫一個 java 程序,對於給定 java 對象,將其轉成 Go 結構體。
比如
public class ScriptDTO {
@JsonProperty("pguid")
private String pguid;
/**
* 腳本類型
*/
@JsonProperty("type")
private String type;
@JsonProperty("rule")
private Rule rule;
@JsonProperty("sha256s")
private List<String> sha256s;
@JsonProperty("param")
private Map<String, Object> param;
@JsonProperty("create_time")
private Long createTime;
}
轉成
type AgentScript struct {
Pguid string `json:"pguid"`
Type string `json:"type"`
Rule Rule `json:"rule"`
CreateTime int64 `json:"create_time"`
Sha256s []string `json:"sha256s"`
Param map[string]any `json:"param"`
}
要求滿足如下條件:
- 類名、字段名、字段類型可以反射方式獲取
- Java 字段類型要轉換爲 go 的對應字段類型
- go 結構體字段與 Java 類定義的字段順序保持一致。
- Java 註釋內容 /** comment */ 寫在 結構體字段定義的後面,以 // 開始;如果沒有則省略。
- 考慮字段沒有 @JsonProperty("rule") 註解的空情形。
- 要求能夠處理 java 裏的各種原子類型,比如 int, Integer, String, Boolean, Long, long; 自定義類型按原樣輸出。
- go 結構體字段要首字母大寫。
- 將 go 結構體寫入用戶主目錄下 ~/ 的文件。文件名是類名的小寫下劃線形式,去掉最前面的下劃線。
- 保持程序的模塊化和易修改,做好錯誤處理。
- 請給出完整可用程序,不要僞代碼。
寫一個 java 完整程序,指定一個 java 包名,對這個包及其子包下的所有 後綴爲 DTO.java ,或 DO.java 的 java 類,根據上述方法生成對應 go 結構體,並寫入對應文件,寫入用戶主目錄下 ~/ 的文件。文件名是類名的小寫下劃線形式,去掉最前面的下劃線。 結構層級與包層級保持一致。
有時,AI 不能一次性生成完整程序,則需要出多道題把答案拼起來。
固定模式代碼
比如設計模式代碼。指定設計模式名稱,則可直接生成對應代碼。
例如:“Go 模板:用代碼生成代碼”一文中用 AI 生成生成器模式代碼。
類似還有工廠、策略模式代碼等。
提供樣例
如果要生成的代碼比較多但有固定樣式,則可以提供樣例。如下所示:
請記住如下樣例:
給定一個 java 枚舉:
public enum DetectionMethodEnum {
PROCESS_HASH("process_hash", "進程Hash檢測"),
private final String type;
private final String desc;
}
生成對應的 go 枚舉爲:
type DetectionMethod string
type DetectionMethodInfo struct {
MethodType string
Desc string
}
const (
ProcessHash DetectionMethod = "PROCESS_HASH"
)
var DetectionMethodMap = map[DetectionMethod]DetectionMethodInfo{
ProcessHash: {
MethodType: "process_hash",
Desc: "進程Hash檢測"
}
}
請嚴格按照樣例,爲下面的 java 枚舉生成 go 枚舉。
@Getter
@AllArgsConstructor
public enum ContainerTypeEnum {
DOCKER("docker", "docker_container"),
CONTAINERD("cri", "cri_containerd"),
CRIO("crio", "crio_container");
private final String type;
private final String name;
}
提供模板
與提供樣例類似。模板通過若干變量生成。
請記住如下樣例:
給定 do 類 DetectionDO, 生成:
type DetectionService interface {
service.BaseService[*models.DetectionDO]
}
type DetectionServiceImpl struct {
service.BaseService[*models.DetectionDO]
}
func NewDetectionService(repo repository.DetectionRepository) DetectionService {
return &DetectionServiceImpl{
BaseService: service.NewMongoService[*models.DetectionDO](repo),
}
}
func init() {
dow.ProvideGlobal[DetectionService](nil, func(injector *do.Injector) (DetectionService, error) {
repo, err := dow.InvokeGlobal[repository.DetectionRepository](nil)
if err != nil {
return nil, err
}
return NewDetectionService(repo), nil
})
}
type DetectionRepository interface {
repository.BaseRepository[*models.DetectionDO]
}
type DetectionRepositoryImpl struct {
repository.BaseRepository[*models.DetectionDO]
}
func NewDetectionRepository(db *mongox.Database) DetectionRepository {
return &DetectionRepositoryImpl{
BaseRepository: repository.NewMongoRepository[*models.DetectionDO](db.Collection(models.DetectionDO{}.TableName())),
}
}
func init() {
dow.ProvideGlobal[DetectionRepository](nil, func(injector *do.Injector) (DetectionRepository, error) {
database, err := mongox.TenantDatabase()
if err != nil {
return nil, err
}
return NewDetectionRepository(database), nil
})
}
請爲 DO 類 IdsFileUploadTaskDO 生成 service 和 repository 代碼。
語言翻譯
將如下 Java 代碼轉換爲 Go 代碼:
public static String[] getCmdOutput(String cmd) throws InterruptedException, IOException {
long start = System.currentTimeMillis();
Process process = new ProcessBuilder().command("sh", "-c", cmd).start();
boolean ret = process.waitFor(3, TimeUnit.SECONDS);
String output = StringUtils.EMPTY;
String error = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);
if (ret) {
output = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);
LOG.info("cmd: {} output: {}", cmd, output);
} else {
LOG.warn("cmd:{} ret is false", cmd);
process.destroyForcibly();
}
long end = System.currentTimeMillis();
LOG.info("exec cmd: {} cost: {} ms", cmd, (end-start));
return new String[] { output, error };
}
分離純函數
很多業務方法,大部分都是純邏輯(輸入相同則輸出也相同,具有引用透明性),只有少量是依賴外部服務的。
這時候,可以運用“分離純函數”的技巧,將方法中的純邏輯與依賴分離。AI 特別適合於生成無語境或無依賴的純函數。
可參考 “改善代碼可測性的若干技巧”和“使用Java函數接口及lambda表達式隔離和模擬外部依賴更容易滴單測”這兩篇文章。
具體方法是: 先對方法進行拆解,把外部依賴部分抽取出來。外部依賴部分可以用函數參數替代,這樣這個方法就變成了一個純函數,可以用 AI 自動生成,並用 AI 生成測試用例和單測。
仔細再審視我們的工程代碼,會發現,其實 80% 都是純邏輯,真正的業務部分可能只佔 20%。經過良好抽象之後,把純邏輯提取出來,把業務部分做成配置,則理論上 80% 的代碼可以用 AI 生成。
AI 代碼糾錯
定義
type ValueModifier[T any] func(T, ...any)
func DuplicateAndModifyElement[T any](list []*T, keyFunc funcs.IdKey[T], mFunc funcs.ValueModifier[*T], args ...any) []*T {
seen := make(map[string]bool)
result := make([]*T, 0, len(list))
for _, elem := range list {
key := keyFunc(*elem)
if !seen[key] {
seen[key] = true
mFunc(elem, args)
result = append(result, elem)
}
}
return result
}
爲什麼 這行報錯,如何修復
pb := []*test.PersonBasicInfo{{Name: "qin", Age: 36}, {Name: "ni", Age: 28}, {Name: "qin", Age: 29}, {Name: "ni", Age: 28}}
undupAndModified := util.DuplicateAndModifyElement(pb, func(info test.PersonBasicInfo) string { return info.Name }, func(p *test.PersonBasicInfo, skills ...string) { p.Skills = skills }, "programming")
AI CodeReview
現在 gitlab 已經集成了 AI Code review 。這些 review 還是相對中肯的。
小結
對於高級程序員來說, AI 是一個強大的工具,真如虎添翼。
如何利用 AI 來提升效率和創造性,是一個很好的話題。
更多姿勢還在解鎖中。。。