Kotlin DSL 风格编程详解

Kotlin DSL 风格编程详解

一、什么是 DSL

DSL(Domain Specific Language) 即领域特定语言,是一种专门为某个特定领域或场景设计的编程语言或语法风格。

核心理念

DSL 的核心是用代码表达"做什么 "(What),而不是"怎么做"(How)。

生活中的类比

点餐场景
复制代码
❌ 普通表达(命令式):
"请走到厨房,打开冰箱,拿出一个鸡蛋,打碎放入锅中,开火加热3分钟,翻面再加热2分钟,装盘,端出来。"

✅ DSL 表达(声明式):
"我要一个煎蛋。"
建房子场景
复制代码
❌ 普通表达:
"先挖地基10米深,然后浇筑混凝土500立方米,然后砌砖1000块,然后安装铝合金窗户..."

✅ DSL 表达:
我要 {
    三室一厅
    两卫
    南北通透
}

二、普通代码 vs DSL 风格对比

2.1 创建对象并设置属性

Java 普通代码
java 复制代码
public class Person {
    private String name;
    private int age;
    private String city;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("张三");
        person.setAge(20);
        person.setCity("北京");

        System.out.println(person.getName());
    }
}
Kotlin 普通代码
kotlin 复制代码
data class Person(
    var name: String = "",
    var age: Int = 0,
    var city: String = ""
)

// 使用
fun main() {
    val person = Person()
    person.name = "张三"
    person.age = 20
    person.city = "北京"

    println(person.name)
}
Kotlin DSL 风格
kotlin 复制代码
data class Person(
    var name: String = "",
    var age: Int = 0,
    var city: String = ""
)

// DSL 构建函数
fun person(block: Person.() -> Unit): Person {
    return Person().apply(block)
}

// 使用
fun main() {
    val person = person {
        name = "张三"
        age = 20
        city = "北京"
    }

    println(person.name)
}

2.2 条件判断

Java 普通代码
java 复制代码
public class Release {
    private String releaseStatus;
    private String releaseRemark;

    public String getReleaseStatus() {
        return releaseStatus;
    }

    public void setReleaseStatus(String releaseStatus) {
        this.releaseStatus = releaseStatus;
    }

    public String getReleaseRemark() {
        return releaseRemark;
    }

    public void setReleaseRemark(String releaseRemark) {
        this.releaseRemark = releaseRemark;
    }
}

public class ConditionUtils {
    public static boolean checkCondition(Release release) {
        return "1".equals(release.getReleaseStatus()) && release.getReleaseRemark() != null;
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Release release = new Release();
        release.setReleaseStatus("1");
        release.setReleaseRemark("备注内容");

        boolean result = ConditionUtils.checkCondition(release);
        System.out.println(result);
    }
}
Kotlin 普通代码
kotlin 复制代码
data class Release(
    var releaseStatus: String? = null,
    var releaseRemark: String? = null
)

// 使用
fun main() {
    val release = Release(
        releaseStatus = "1",
        releaseRemark = "备注内容"
    )

    val result = release.releaseStatus == "1" && release.releaseRemark != null
    println(result)
}
Kotlin DSL 风格
kotlin 复制代码
data class Release(
    var releaseStatus: String? = null,
    var releaseRemark: String? = null
)

// DSL 条件构建器
class ConditionBuilder<T> {
    private val conditions = mutableListOf<(T) -> Boolean>()

    fun field(property: kotlin.reflect.KProperty1<T, *>, value: Any?) {
        conditions.add { data -> property.get(data) == value }
    }

    fun fieldIsNotNull(property: kotlin.reflect.KProperty1<T, *>) {
        conditions.add { data -> property.get(data) != null }
    }

    fun build(): (T) -> Boolean = { data ->
        conditions.all { it(data) }
    }
}

// DSL 函数
fun <T> condition(block: ConditionBuilder<T>.() -> Unit): (T) -> Boolean {
    val builder = ConditionBuilder<T>()
    builder.block()
    return builder.build()
}

// 使用
fun main() {
    val release = Release(
        releaseStatus = "1",
        releaseRemark = "备注内容"
    )

    val checkCondition = condition<Release> {
        field(Release::releaseStatus, "1")
        fieldIsNotNull(Release::releaseRemark)
    }

    val result = checkCondition(release)
    println(result)  // true
}

2.3 构建列表

Java 普通代码
java 复制代码
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("苹果");
        list.add("香蕉");
        list.add("橙子");

        for (String item : list) {
            System.out.println(item);
        }
    }
}
Kotlin 普通代码
kotlin 复制代码
fun main() {
    val list = mutableListOf<String>()
    list.add("苹果")
    list.add("香蕉")
    list.add("橙子")

    for (item in list) {
        println(item)
    }
}
Kotlin DSL 风格
kotlin 复制代码
// DSL 列表构建函数
fun <T> list(block: MutableList<T>.() -> Unit): List<T> {
    return mutableListOf<T>().apply(block)
}

// 使用
fun main() {
    val fruits = list<String> {
        add("苹果")
        add("香蕉")
        add("橙子")
    }

    fruits.forEach { println(it) }
}

2.4 构建嵌套对象

Java 普通代码
java 复制代码
import java.util.ArrayList;
import java.util.List;

public class Address {
    private String province;
    private String city;
    private String street;

    public String getProvince() { return province; }
    public void setProvince(String province) { this.province = province; }
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    public String getStreet() { return street; }
    public void setStreet(String street) { this.street = street; }
}

public class User {
    private String name;
    private int age;
    private Address address;
    private List<String> hobbies;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
    public List<String> getHobbies() { return hobbies; }
    public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
}

// 使用
public class Main {
    public static void main(String[] args) {
        User user = new User();
        user.setName("张三");
        user.setAge(25);

        Address address = new Address();
        address.setProvince("广东省");
        address.setCity("深圳市");
        address.setStreet("科技路");
        user.setAddress(address);

        List<String> hobbies = new ArrayList<>();
        hobbies.add("游泳");
        hobbies.add("阅读");
        user.setHobbies(hobbies);

        System.out.println(user.getName());
    }
}
Kotlin DSL 风格
kotlin 复制代码
data class Address(
    var province: String = "",
    var city: String = "",
    var street: String = ""
)

data class User(
    var name: String = "",
    var age: Int = 0,
    var address: Address = Address(),
    var hobbies: MutableList<String> = mutableListOf()
)

// DSL 构建函数
fun user(block: User.() -> Unit): User = User().apply(block)

fun User.address(block: Address.() -> Unit) {
    address = Address().apply(block)
}

// 使用
fun main() {
    val user = user {
        name = "张三"
        age = 25

        address {
            province = "广东省"
            city = "深圳市"
            street = "科技路"
        }

        hobbies = mutableListOf("游泳", "阅读")
    }

    println(user.name)
    println(user.address.city)
}

三、Kotlin 实现 DSL 的核心语法特性

Kotlin DSL 之所以简洁优雅,主要依赖以下几个核心语法特性:

3.1 带接收者的 Lambda(Lambda with Receiver)

这是 Kotlin DSL 最重要的特性。

语法说明
kotlin 复制代码
// 普通 Lambda
block: (T) -> Unit
// 调用方式:block(receiver)
// Lambda 内部:需要用参数名访问 receiver

// 带接收者的 Lambda
block: T.() -> Unit
// 调用方式:receiver.block()
// Lambda 内部:this 指向 receiver,可直接访问其成员
Java 对比
java 复制代码
// Java 只有普通 Lambda(Java 8+)
// 没有带接收者的 Lambda

// Java 实现
public class Person {
    private String name;
    private int age;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

public class PersonBuilder {
    public static void withPerson(Person person, Consumer<Person> block) {
        block.accept(person);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        PersonBuilder.withPerson(person, p -> {
            p.setName("张三");  // 必须用参数名 p
            p.setAge(20);
        });
    }
}
Kotlin 实现
kotlin 复制代码
data class Person(
    var name: String = "",
    var age: Int = 0
)

fun person(block: Person.() -> Unit): Person {
    return Person().apply(block)
}

// 使用
fun main() {
    val person = person {
        name = "张三"  // 直接访问,不需要参数名
        age = 20
    }
}
对比总结
特性 Java Kotlin
Lambda 类型 (T) -> Unit T.() -> Unit
调用方式 block.accept(receiver) receiver.block()
内部访问 p.setName("张三") name = "张三"
语法糖 ❌ 无 ✅ this 可省略

3.2 扩展函数(Extension Function)

Java 对比
java 复制代码
// Java:必须写工具类
public class StringUtils {
    public static boolean isNotEmpty(String str) {
        return str != null && !str.isEmpty();
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        String name = "张三";
        boolean result = StringUtils.isNotEmpty(name);
    }
}
Kotlin 实现
kotlin 复制代码
// Kotlin:扩展函数
fun String.isNotEmpty(): Boolean {
    return this != null && this.isNotEmpty()
}

// 使用
fun main() {
    val name = "张三"
    val result = name.isNotEmpty()  // 像调用成员方法一样
}
在 DSL 中的应用
kotlin 复制代码
// 为 String 添加 DSL 风格的扩展函数
fun String.ifNotEmpty(block: (String) -> Unit) {
    if (this.isNotEmpty()) {
        block(this)
    }
}

// 使用
fun main() {
    val name = "张三"

    name.ifNotEmpty {
        println("名字是: $it")
    }
}
对比总结
特性 Java Kotlin
实现方式 工具类静态方法 扩展函数
调用方式 Utils.method(obj) obj.method()
语法体验 函数调用 像成员方法

3.3 Lambda 在括号外

Java 对比
java 复制代码
// Java:Lambda 必须在括号内
public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");

        // Lambda 必须在括号内
        list.forEach(item -> System.out.println(item));
    }
}
Kotlin 实现
kotlin 复制代码
fun main() {
    val list = listOf("a", "b", "c")

    // 方式1:Lambda 在括号内
    list.forEach({ item -> println(item) })

    // 方式2:Lambda 在括号外(语法糖)
    list.forEach { item ->
        println(item)
    }

    // 方式3:如果只有一个参数,可用 it
    list.forEach { println(it) }
}
在 DSL 中的应用
kotlin 复制代码
data class Person(var name: String = "", var age: Int = 0)

// 如果最后一个参数是 Lambda,可以放在括号外
fun person(block: Person.() -> Unit): Person = Person().apply(block)

fun main() {
    // 这些写法都等价
    val p1 = person({ name = "张三" })  // Lambda 在括号内

    val p2 = person() { name = "张三" } // Lambda 在括号外

    val p3 = person { name = "张三" }   // 括号可省略
}
对比总结
特性 Java Kotlin
Lambda 位置 必须在括号内 可在括号外
空括号处理 必须写 () 可省略 ()
DSL 友好度 ❌ 一般 ✅ 非常友好

3.4 中缀函数(Infix Function)

Java 对比
java 复制代码
// Java:只能用普通方法调用
public class Pair {
    private String first;
    private String second;

    public Pair(String first, String second) {
        this.first = first;
        this.second = second;
    }

    public String getFirst() { return first; }
    public String getSecond() { return second; }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Pair pair = new Pair("key", "value");
        System.out.println(pair.getFirst());
    }
}
Kotlin 实现
kotlin 复制代码
// 中缀函数
infix fun String.to(that: String): Pair<String, String> {
    return Pair(this, that)
}

// 使用
fun main() {
    // 普通调用
    val pair1 = "key".to("value")

    // 中缀调用(更接近自然语言)
    val pair2 = "key" to "value"

    println(pair2.first)  // key
}
在 DSL 中的应用
kotlin 复制代码
// Map 构建
fun main() {
    // 普通写法
    val map1 = mapOf(Pair("name", "张三"), Pair("age", "20"))

    // 中缀函数 DSL 风格
    val map2 = mapOf(
        "name" to "张三",
        "age" to "20"
    )

    println(map2["name"])
}
对比总结
特性 Java Kotlin
调用语法 obj.method(arg) obj method arg
自然语言感 ❌ 无 ✅ 像 "key to value"
DSL 友好度 ❌ 一般 ✅ 非常友好

3.5 操作符重载(Operator Overloading)

Java 对比
java 复制代码
// Java:不支持操作符重载
public class Money {
    private int amount;

    public Money(int amount) {
        this.amount = amount;
    }

    public int getAmount() { return amount; }

    // 只能用普通方法
    public Money add(Money other) {
        return new Money(this.amount + other.amount);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Money m1 = new Money(100);
        Money m2 = new Money(50);
        Money total = m1.add(m2);  // 只能调用方法
    }
}
Kotlin 实现
kotlin 复制代码
data class Money(val amount: Int) {
    // 操作符重载
    operator fun plus(other: Money): Money {
        return Money(this.amount + other.amount)
    }

    operator fun minus(other: Money): Money {
        return Money(this.amount - other.amount)
    }
}

// 使用
fun main() {
    val m1 = Money(100)
    val m2 = Money(50)

    val total = m1 + m2  // 使用 + 操作符
    val diff = m1 - m2   // 使用 - 操作符

    println(total.amount)  // 150
}
在 DSL 中的应用
kotlin 复制代码
data class Path(val segments: MutableList<String> = mutableListOf()) {
    operator fun String.unaryPlus() {
        segments.add(this)
    }

    operator fun plus(other: Path): Path {
        return Path((segments + other.segments).toMutableList())
    }
}

fun path(block: Path.() -> Unit): Path = Path().apply(block)

// 使用
fun main() {
    val p = path {
        +"home"
        +"user"
        +"documents"
    }

    println(p.segments)  // [home, user, documents]
}
对比总结
特性 Java Kotlin
操作符重载 ❌ 不支持 ✅ 支持
调用方式 m1.add(m2) m1 + m2
DSL 友好度 ❌ 差 ✅ 好

四、Java vs Kotlin 实现 DSL 完整对比

4.1 场景:构建 HTML

Java 实现
java 复制代码
import java.util.ArrayList;
import java.util.List;

// HTML 标签基类
public abstract class HtmlElement {
    protected String tagName;
    protected List<HtmlElement> children = new ArrayList<>();
    protected String textContent;

    public void addChild(HtmlElement element) {
        children.add(element);
    }

    public void setText(String text) {
        this.textContent = text;
    }

    public abstract String render();
}

// Div 标签
public class Div extends HtmlElement {
    public Div() {
        this.tagName = "div";
    }

    @Override
    public String render() {
        StringBuilder sb = new StringBuilder();
        sb.append("<").append(tagName).append(">");
        if (textContent != null) {
            sb.append(textContent);
        }
        for (HtmlElement child : children) {
            sb.append(child.render());
        }
        sb.append("</").append(tagName).append(">");
        return sb.toString();
    }
}

// P 标签
public class P extends HtmlElement {
    public P() {
        this.tagName = "p";
    }

    @Override
    public String render() {
        return "<p>" + (textContent != null ? textContent : "") + "</p>";
    }
}

// HTML 构建器
public class HtmlBuilder {
    private Div root;

    public HtmlBuilder() {
        this.root = new Div();
    }

    public HtmlBuilder div(Consumer<Div> block) {
        Div div = new Div();
        block.accept(div);
        root.addChild(div);
        return this;
    }

    public HtmlBuilder p(String text) {
        P p = new P();
        p.setText(text);
        root.addChild(p);
        return this;
    }

    public String build() {
        return root.render();
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        HtmlBuilder builder = new HtmlBuilder();
        String html = builder
            .div(div -> {
                div.addChild(new P());
                // 很难继续嵌套...
            })
            .p("Hello World")
            .build();

        System.out.println(html);
    }
}
Kotlin DSL 实现
kotlin 复制代码
// HTML 标签基类
open class Tag(val name: String) {
    val children = mutableListOf<Tag>()
    val attributes = mutableMapOf<String, String>()

    fun <T : Tag> initTag(tag: T, init: T.() -> Unit): T {
        tag.init()
        children.add(tag)
        return tag
    }

    override fun toString(): String {
        val attrs = if (attributes.isEmpty()) "" else attributes.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
        val content = children.joinToString("")
        return "<$name $attrs>$content</$name>"
    }
}

// 具体标签
class HTML : Tag("html") {
    fun head(init: HEAD.() -> Unit) = initTag(HEAD(), init)
    fun body(init: BODY.() -> Unit) = initTag(BODY(), init)
}

class HEAD : Tag("head") {
    fun title(init: TITLE.() -> Unit) = initTag(TITLE(), init)
}

class TITLE : Tag("title")

class BODY : Tag("body") {
    fun div(init: DIV.() -> Unit) = initTag(DIV(), init)
    fun p(init: P.() -> Unit) = initTag(P(), init)
}

class DIV : Tag("div") {
    fun p(init: P.() -> Unit) = initTag(P(), init)
    fun span(init: SPAN.() -> Unit) = initTag(SPAN(), init)
}

class P : Tag("p") {
    operator fun String.unaryPlus() {
        children.add(Text(this))
    }
}

class SPAN : Tag("span")

class Text(private val text: String) : Tag("") {
    override fun toString() = text
}

// DSL 入口函数
fun html(init: HTML.() -> Unit): HTML {
    return HTML().apply(init)
}

// 使用
fun main() {
    val result = html {
        head {
            title {
                // 标题内容
            }
        }
        body {
            div {
                p {
                    +"Hello World"
                }
                p {
                    +"This is a paragraph"
                }
            }
            div {
                p {
                    +"Another paragraph"
                }
            }
        }
    }

    println(result)
}

4.2 场景:构建 SQL 查询

Java 实现
java 复制代码
import java.util.ArrayList;
import java.util.List;

public class SqlBuilder {
    private String tableName;
    private List<String> columns = new ArrayList<>();
    private List<String> whereConditions = new ArrayList<>();
    private String orderBy;
    private Integer limit;

    public SqlBuilder select(String... cols) {
        for (String col : cols) {
            columns.add(col);
        }
        return this;
    }

    public SqlBuilder selectAll() {
        columns.add("*");
        return this;
    }

    public SqlBuilder from(String table) {
        this.tableName = table;
        return this;
    }

    public SqlBuilder where(String condition) {
        whereConditions.add(condition);
        return this;
    }

    public SqlBuilder orderBy(String column) {
        this.orderBy = column;
        return this;
    }

    public SqlBuilder limit(int n) {
        this.limit = n;
        return this;
    }

    public String build() {
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT ");

        if (columns.isEmpty()) {
            sb.append("*");
        } else {
            sb.append(String.join(", ", columns));
        }

        sb.append(" FROM ").append(tableName);

        if (!whereConditions.isEmpty()) {
            sb.append(" WHERE ");
            sb.append(String.join(" AND ", whereConditions));
        }

        if (orderBy != null) {
            sb.append(" ORDER BY ").append(orderBy);
        }

        if (limit != null) {
            sb.append(" LIMIT ").append(limit);
        }

        return sb.toString();
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        String sql = new SqlBuilder()
            .select("id", "name", "age")
            .from("users")
            .where("age > 18")
            .where("status = 'active'")
            .orderBy("name")
            .limit(10)
            .build();

        System.out.println(sql);
        // SELECT id, name, age FROM users WHERE age > 18 AND status = 'active' ORDER BY name LIMIT 10
    }
}
Kotlin DSL 实现
kotlin 复制代码
class SqlBuilder {
    private var tableName = ""
    private val columns = mutableListOf<String>()
    private val whereConditions = mutableListOf<String>()
    private var orderByClause: String? = null
    private var limitValue: Int? = null

    fun select(vararg cols: String) {
        columns.addAll(cols)
    }

    fun selectAll() {
        columns.add("*")
    }

    fun from(table: String) {
        tableName = table
    }

    fun where(condition: String) {
        whereConditions.add(condition)
    }

    fun orderBy(column: String) {
        orderByClause = column
    }

    fun limit(n: Int) {
        limitValue = n
    }

    fun build(): String {
        val cols = if (columns.isEmpty()) "*" else columns.joinToString(", ")

        val where = if (whereConditions.isNotEmpty()) {
            " WHERE ${whereConditions.joinToString(" AND ")}"
        } else ""

        val order = orderByClause?.let { " ORDER BY $it" } ?: ""
        val lim = limitValue?.let { " LIMIT $it" } ?: ""

        return "SELECT $cols FROM $tableName$where$order$lim"
    }
}

// DSL 函数
fun sql(block: SqlBuilder.() -> String): String {
    val builder = SqlBuilder()
    builder.block()
    return builder.build()
}

// DSL 扩展函数
fun SqlBuilder.select(block: SelectBuilder.() -> Unit) {
    val selectBuilder = SelectBuilder()
    selectBuilder.block()
    columns.addAll(selectBuilder.columns)
}

class SelectBuilder {
    val columns = mutableListOf<String>()

    operator fun String.unaryPlus() {
        columns.add(this)
    }
}

// 使用
fun main() {
    // 简单 DSL
    val sql1 = sql {
        select("id", "name", "age")
        from("users")
        where("age > 18")
        where("status = 'active'")
        orderBy("name")
        limit(10)
        build()
    }

    println(sql1)

    // 更优雅的 DSL(使用 + 操作符)
    val sql2 = sql {
        select {
            +"id"
            +"name"
            +"age"
        }
        from("users")
        where("age > 18")
        where("status = 'active'")
        orderBy("name")
        limit(10)
        build()
    }

    println(sql2)
}

五、总结

语法特性对比表

特性 Java Kotlin DSL 友好度
带接收者的 Lambda ❌ 不支持 ✅ 支持 ⭐⭐⭐⭐⭐
扩展函数 ❌ 不支持 ✅ 支持 ⭐⭐⭐⭐
Lambda 在括号外 ❌ 不支持 ✅ 支持 ⭐⭐⭐⭐⭐
中缀函数 ❌ 不支持 ✅ 支持 ⭐⭐⭐⭐
操作符重载 ❌ 不支持 ✅ 支持 ⭐⭐⭐⭐
属性访问简化 ❌ getter/setter ✅ 直接访问 ⭐⭐⭐⭐
默认参数 ❌ 不支持 ✅ 支持 ⭐⭐⭐
命名参数 ❌ 不支持 ✅ 支持 ⭐⭐⭐

DSL 适用场景

场景 说明
配置构建 Gradle、Kotlin DSL 配置
UI 布局 Compose、Anko
数据查询 SQL DSL、MongoDB DSL
测试框架 Kotest、MockK
HTML/XML Kotlinx.html
表单验证 本项目的 condition DSL

核心要点

  1. DSL 本质:用代码表达"做什么",而不是"怎么做"
  2. Kotlin 优势:多个语法特性共同作用,让 DSL 简洁优雅
  3. Java 现状:可以用 Builder 模式模拟,但代码量更大
  4. 最佳实践:DSL 要语义清晰、易于理解,不要过度设计
相关推荐
枫叶丹43 小时前
【HarmonyOS 6.0】ArkWeb 深度解读:getPageOffset20 与网页滚动偏移量获取能力的演进
开发语言·华为·harmonyos
独特的螺狮粉3 小时前
开源鸿蒙跨平台Flutter开发:室内探险游戏应用
开发语言·flutter·游戏·华为·开源·harmonyos·鸿蒙
坏小虎3 小时前
~/.zshrc 和 ~/.bash_profile 详细介绍与区别
开发语言·bash
独特的螺狮粉4 小时前
开源鸿蒙跨平台Flutter开发:喝水时间提醒应用
开发语言·flutter·华为·信息可视化·开源·harmonyos·鸿蒙
橘子编程4 小时前
GoF 23 种设计模式完整知识总结与使用教程
java·c语言·开发语言·python·设计模式
玖釉-4 小时前
告别 Shared Memory 瓶颈:Vulkan Subgroup 架构解析与硬核实战指南
开发语言·c++·windows·图形渲染
lly2024064 小时前
SQL UPDATE 语句详解
开发语言
君以思为故4 小时前
认识Linux -- 线程同步与互斥
java·开发语言
fetasty4 小时前
chroot的Linux服务配置-当云服务器真正用起来
android·linux·服务器