函数式接口:现代编程的利器

1. 引言

在软件开发的演进过程中,函数式编程(Functional Programming, FP)逐渐显露头角,成为解决复杂问题的有效工具之一。函数式接口作为函数式编程的核心概念之一,其重要性不言而喻。本文将深入探讨函数式接口的概念、应用以及它在现代编程中的重要作用。

2. 函数式接口的基础

函数式接口是函数式编程中一个至关重要的概念,它为编写简洁、可维护的代码提供了强大的支持。在本章节中,我们将深入探讨函数式接口的基本概念、特性以及它在Java语言中的实现。

2.1 定义与特性

函数式接口是指只包含一个抽象方法的接口。这种接口的设计理念是将行为抽象化,使得我们可以将方法作为参数传递给其他方法,或者将方法作为返回值返回。函数式接口通常用于实现高阶函数,即函数的参数或返回值也是函数。

2.2 与普通接口的区别

普通接口可以包含多个方法,而函数式接口则限制为只有一个抽象方法。这种限制使得函数式接口非常适合作为Lambda表达式的目标类型。Lambda表达式可以被视为匿名的函数式接口实例,它允许我们以一种非常简洁的方式实现函数式接口。

2.3 Java中的实现

Java 8是Java语言中一个重要的里程碑,它引入了java.util.function包,这个包中定义了一系列的函数式接口,例如:

  • Supplier<T>:提供类型为T的对象实例。
  • Consumer<T>:接受类型为T的对象,并对其执行某些操作。
  • Function<T, R>:接受类型为T的对象,返回类型为R的对象。
  • Predicate<T>:接受类型为T的对象,并返回一个布尔值,用于表示断言。
  • UnaryOperator<T>:接受类型为T的对象,返回同一类型的结果。
  • BinaryOperator<T>:接受两个类型为T的对象,返回同一类型的结果。

这些接口为Java开发者提供了强大的工具,使得他们可以更加方便地实现函数式编程。

2.4 函数式接口的实现示例

让我们通过一个简单的例子来展示如何实现一个函数式接口:

@FunctionalInterface
public interface SimpleMathOperation {int operation(int a, int b);
}// 使用Lambda表达式实现SimpleMathOperation接口
SimpleMathOperation add = (a, b) -> a + b;
int result = add.operation(5, 3); // 结果为8

在上面的例子中,我们定义了一个简单的函数式接口SimpleMathOperation,它包含一个接受两个整数参数并返回一个整数结果的方法operation。然后,我们使用Lambda表达式(a, b) -> a + b来创建一个实现了该接口的实例,并调用它来执行加法操作。

3. 函数式接口的使用场景

函数式接口因其简洁、灵活的特性,在现代软件开发中扮演着越来越重要的角色。本章节将深入探讨函数式接口在不同编程场景中的应用,并提供丰富的代码示例,以展示它们如何帮助我们编写更加优雅和高效的代码。

3.1 并发编程中的应用

在并发编程中,函数式接口可以简化线程管理,并提高程序的可读性和可维护性。例如,Java 8中的CompletableFuture提供了supplyAsync方法,它接受一个Supplier函数式接口,用于异步执行任务:

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 模拟耗时操作try {Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return 42; // 任务结果
});future.thenAccept(System.out::println); // 处理结果

在这个示例中,我们使用supplyAsync来异步执行一个耗时操作,并在操作完成后处理结果。使用System.out::println作为方法引用,简化了Lambda表达式的书写。

3.2 事件驱动编程中的应用

在事件驱动编程中,函数式接口常用于定义事件处理器。例如,在使用JavaFX进行GUI编程时,可以利用EventHandler接口处理按钮点击事件:

Button button = new Button("Click me");
button.setOnAction(event -> {System.out.println("Button was clicked!");
});

这里,我们使用Lambda表达式创建了一个实现了EventHandler<ActionEvent>接口的匿名类,用于响应按钮点击事件。这种方式比传统的匿名内部类更加简洁。

3.3 数据流处理中的应用

在处理数据流时,函数式接口提供了一种声明式的方法来转换和聚合数据。以下是使用Java 8的Stream API对一组数字进行过滤和映射的示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
long count = numbers.stream().filter(n -> n % 2 == 0) // 使用Predicate接口过滤偶数.map(n -> n * n)       // 使用Function接口进行平方操作.count();              // 计算结果的数量System.out.println("Count of squared even numbers: " + count);

在这个例子中,filtermap方法分别接受PredicateFunction接口的实现,用于对流中的元素进行过滤和转换。这种方式使得数据处理变得非常直观和易于理解。

3.4 策略模式的实现

函数式接口也可以用于实现策略模式,允许在运行时动态选择算法或行为。以下是使用函数式接口实现策略模式的示例:

@FunctionalInterface
interface CalculationStrategy {int calculate(int x, int y);
}// 实现加法策略
CalculationStrategy add = (x, y) -> x + y;
// 实现乘法策略
CalculationStrategy multiply = (x, y) -> x * y;public class Calculator {private CalculationStrategy strategy;public void setStrategy(CalculationStrategy strategy) {this.strategy = strategy;}public int executeStrategy(int x, int y) {return strategy.calculate(x, y);}
}// 使用Calculator
Calculator calculator = new Calculator();
calculator.setStrategy(add);
System.out.println(calculator.executeStrategy(5, 3)); // 输出 8calculator.setStrategy(multiply);
System.out.println(calculator.executeStrategy(5, 3)); // 输出 15

在这个示例中,CalculationStrategy是一个函数式接口,定义了一个calculate方法。我们为这个接口提供了两个实现:一个用于加法,一个用于乘法。Calculator类使用这个接口来动态改变其行为,从而实现了策略模式。

3.5 排序和搜索算法的实现

函数式接口也可以用于实现排序和搜索算法。例如,Java中的ArraysCollections类提供了sort方法的重载版本,它们接受Comparator函数式接口作为参数:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, String::compareTo); // 升序排序names.sort((a, b) -> b.compareTo(a)); // 降序排序

在这个例子中,我们首先使用String::compareTo作为方法引用对列表进行升序排序,然后通过Lambda表达式实现降序排序。

3.6 构建自定义函数式接口

除了Java内置的函数式接口,我们还可以根据自己的需求定义自定义的函数式接口。例如,假设我们需要一个接口来执行一些条件检查:

@FunctionalInterface
interface ConditionChecker<T> {boolean check(T t);
}List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream().filter(new ConditionChecker<Integer>() {@Overridepublic boolean check(Integer number) {return number % 2 == 0;}}).collect(Collectors.toList());System.out.println(evenNumbers); // 输出 [2, 4]

在这个示例中,我们定义了一个ConditionChecker接口,它接受一个类型为T的对象并返回一个布尔值。然后,我们创建了一个实现了ConditionChecker的匿名类实例,并在Stream API的filter方法中使用它来筛选出偶数。

4. Java中的函数式接口

Java 8通过java.util.function包引入了一系列函数式接口,它们极大地丰富了Java编程的表达能力,使得代码更加简洁和易于理解。这些接口在不同的编程场景中扮演着关键角色。以下是对这些接口的详细介绍及其使用场景的示例。

4.1 Supplier<T>接口

使用场景:当需要延迟初始化或按需创建对象时,Supplier<T>接口非常有用。

Supplier<Person> personSupplier = () -> new Person("John Doe", 30);
Person person = personSupplier.get(); // 按需创建Person对象

4.2 Consumer<T>接口

使用场景Consumer<T>接口适用于执行对单个元素的操作,如日志记录、用户界面更新等。

Consumer<String> logger = (message) -> System.out.println("Log: " + message);
logger.accept("This is an informational message."); // 日志记录

4.3 Function<T, R>接口

使用场景Function<T, R>接口用于对数据进行转换,常见于数据处理和转换操作。

Function<String, Integer> stringToLength = String::length;
Integer length = stringToLength.apply("Hello, World!"); // 字符串长度转换

4.4 Predicate<T>接口

使用场景Predicate<T>接口用于条件检查,如过滤集合中的元素。

Predicate<Integer> isEven = num -> num % 2 == 0;
boolean hasEvenNumber = Arrays.stream(new int[]{1, 2, 3, 4, 5}).anyMatch(isEven); // 检查是否有偶数

4.5 UnaryOperator<T>接口

使用场景:作为Function<T, T>的特化,UnaryOperator<T>接口适用于对同一类型的数据执行操作,如数值的转换。

UnaryOperator<Integer> increment = n -> n + 1;
int incrementedValue = increment.apply(5); // 数值加1操作

4.6 BinaryOperator<T>接口

使用场景BinaryOperator<T>接口用于对两个相同类型的数据执行二元操作,如求两个数的最大值。

BinaryOperator<Integer> max = (a, b) -> Math.max(a, b);
int maxValue = max.apply(10, 20); // 求两个数的最大值

4.7 BiFunction<T, U, R>接口

使用场景BiFunction<T, U, R>接口适用于需要两个输入参数的复杂映射操作,如基于两个参数计算结果。

BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b;
int result = sum.apply(5, 10); // 两个整数求和

4.8 BiPredicate<T, U>接口

使用场景BiPredicate<T, U>接口用于两个参数的条件判断,适用于复杂的过滤逻辑。

BiPredicate<Integer, Integer> isDivisible = (dividend, divisor) -> dividend % divisor == 0;
boolean isDivisibleResult = isDivisible.test(10, 5); // 检查是否能整除

4.9 Comparator<T>接口

使用场景Comparator<T>接口用于定义对象的比较规则,常用于排序操作。

Comparator<Person> byAge = Comparator.comparingInt(Person::getAge);
List<Person> sortedByAge = people.stream().sorted(byAge).collect(Collectors.toList()); // 按年龄排序

4.10 组合函数式接口

使用场景:组合函数式接口可以创建复杂的操作链,如数据处理流水线。

Function<String, Integer> toLength = String::length;
Function<Integer, Integer> increment = n -> n + 1;Function<String, Integer> processString = toLength.andThen(increment);
int processedResult = processString.apply("Kimi"); // 字符串长度加1

5. 高阶函数和Lambda表达式

高阶函数和Lambda表达式是函数式编程的核心概念,它们允许我们以声明式的方式处理数据和逻辑。在Java中,高阶函数是指可以接受另一个函数作为参数或者返回一个函数的函数。Lambda表达式提供了一种简洁的方式来实现函数式接口,使得代码更加简洁和易于理解。本章节将详细介绍高阶函数和Lambda表达式的概念、特性以及实际应用示例。

5.1 高阶函数的概念

使用场景:高阶函数在需要根据不同条件执行不同操作时非常有用,例如策略模式的实现。

@FunctionalInterface
interface Strategy<T> {T execute(Object input);
}// 定义一个高阶函数,它接受一个策略并返回执行结果
<T> T executeStrategy(Strategy<T> strategy, Object input) {return strategy.execute(input);
}// 实现一个具体的策略
Strategy<Double> addTax = (input) -> (Double) input * 1.05;double result = executeStrategy(addTax, 100.0); // 结果为105.0

5.2 Lambda表达式的概念

使用场景:Lambda表达式在需要匿名内部类时非常有用,特别是在实现函数式接口时。

// 使用Lambda表达式实现Runnable接口
Runnable r = () -> System.out.println("Hello, Lambda!");
r.run();

5.3 Lambda表达式与函数式接口的结合

使用场景:Lambda表达式与函数式接口结合使用,可以简化代码,特别是在使用Stream API时。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream().filter(name -> name.length() > 4).sorted((a, b) -> b.compareTo(a)).forEach(name -> System.out.println(name));

5.4 方法引用

使用场景:方法引用是Lambda表达式的一种更简洁的形式,特别适用于引用已有方法。

// 使用方法引用作为Lambda表达式
Integer sum = Arrays.stream(new Integer[]{1, 2, 3, 4}).reduce(0, Integer::sum); // 使用Integer::sum作为方法引用

5.5 构造器引用

使用场景:构造器引用允许我们创建对象的实例,而不需要显式地调用构造函数。

List<Person> people = Arrays.asList(new Person("John", 25),new Person("Jane", 28)
);// 使用构造器引用简化对象的创建
List<Person> morePeople = people.stream().map(Person::new).collect(Collectors.toList());

5.6 数组和可变长参数

使用场景:Lambda表达式可以与数组和可变长参数结合使用,简化方法调用。

// 使用Lambda表达式和数组
Arrays.stream(new String[]{"Hello", "World"}).forEach(System.out::println);// 使用Lambda表达式和可变长参数
public static <T> void printAll(Consumer<T>... consumers) {for (Consumer<T> consumer : consumers) {consumer.accept(null);}
}printAll(System.out::println, System.err::println);

5.7 异常处理

使用场景:Lambda表达式可以与异常处理结合使用,使得错误处理更加简洁。

public <T> T processWithException(Function<String, T> func, String arg) {return func.apply(arg);
}public static void main(String[] args) {try {processWithException(s -> {if ("error".equals(s)) throw new IllegalArgumentException("Error!");return s.toUpperCase();}, "error");} catch (Exception e) {e.printStackTrace();}
}

5.8 闭包

使用场景:Lambda表达式支持闭包,允许Lambda表达式捕获并包含它们的上下文中的变量。

Function<Integer, Integer> adder = (initial) -> i -> i + initial;
Function<Integer> add5 = adder.apply(5);
System.out.println(add5.apply(10)); // 输出15

5.9 组合Lambda表达式

使用场景:Lambda表达式可以组合使用,形成复杂的逻辑链。

Function<String, Integer> toLength = String::length;
Function<Integer, Integer> increment = n -> n + 1;Function<String, Integer> processString = toLength.andThen(increment);
String input = "Lambda";
System.out.println(processString.apply(input)); // 输出7(字符串"Lambda"的长度加1)

6. 函数式接口的高级特性

Java 8不仅引入了函数式接口的概念,还为这些接口提供了一些高级特性,使得它们更加强大和灵活。这些特性包括默认方法、静态方法以及与方法引用和构造器引用的结合使用。本章节将详细介绍这些高级特性,并提供丰富的示例来展示它们的应用。

6.1 默认方法

默认方法允许接口提供默认实现的方法,这使得我们可以在不破坏现有实现的情况下,向接口添加新的方法。

使用场景:当需要向现有接口添加新功能,同时又不想让现有实现者进行大量修改时。

@FunctionalInterface
interface MyFunctionalInterface {default void defaultMethod() {System.out.println("Default method implementation");}
}MyFunctionalInterface myInterface = () -> {// 特定实现
};
myInterface.defaultMethod(); // 调用默认方法

6.2 静态方法

静态方法允许接口提供工具方法,这些方法可以在接口本身上直接调用,而不需要实例化接口。

使用场景:当需要提供一些与接口功能相关的工具方法时。

@FunctionalInterface
interface Converter<F, T> {static <F, T> Converter<F, T> identity() {return (f) -> f;}T convert(F from);
}Converter<String, Integer> converter = Converter.identity();
Integer result = converter.convert("123"); // 使用静态方法identity()创建的转换器

6.3 默认方法与Lambda表达式的结合

默认方法可以与Lambda表达式结合使用,提供灵活的行为。

使用场景:当需要在Lambda表达式中使用接口的默认方法时。

@FunctionalInterface
interface Processor {default void process() {System.out.println("Processing");}void perform();
}Processor processor = () -> {System.out.println("Performing a task");
}::process;processor.perform(); // 调用Lambda表达式中的perform方法
processor.process(); // 调用接口的默认方法process

6.4 静态方法与Lambda表达式的结合

静态方法可以与Lambda表达式结合使用,创建更加灵活和强大的工具。

使用场景:当需要在Lambda表达式中使用接口的静态方法时。

@FunctionalInterface
interface MathOperation {static MathOperation add(int a, int b) {return (x) -> x + a + b;}int operate(int x);
}MathOperation addFive = MathOperation.add(2, 3);
int result = addFive.operate(10); // 输出23

6.5 链式调用

通过默认方法和静态方法,可以实现链式调用,使得代码更加流畅。

使用场景:当需要创建一个流畅的API,允许调用者以链式的方式调用多个方法时。

@FunctionalInterface
interface FluentProcessor {default FluentProcessor next() {System.out.println("Next step in the process");return this;}default void start() {System.out.println("Starting the process");next();}
}FluentProcessor fp = new FluentProcessor() {// 具体实现
};fp.start().next(); // 链式调用start和next

6.6 方法引用与构造器引用

方法引用和构造器引用可以与默认方法和静态方法结合,简化代码。

使用场景:当需要在Lambda表达式中引用已有的方法或构造器时。

@FunctionalInterface
interface Action {void perform();
}Action action = this::method; // 方法引用class MyClass {void method() {System.out.println("Method called");}
}// 构造器引用
Function<String, MyClass> constructor = MyClass::new;
MyClass myClass = constructor.apply("Parameter");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/19063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【408真题】2009-28

“接”是针对题目进行必要的分析&#xff0c;比较简略&#xff1b; “化”是对题目中所涉及到的知识点进行详细解释&#xff1b; “发”是对此题型的解题套路总结&#xff0c;并结合历年真题或者典型例题进行运用。 涉及到的知识全部来源于王道各科教材&#xff08;2025版&…

C++进程间通信 匿名管道和命名管道

C进程间通信 匿名管道和命名管道 1. 匿名管道匿名管道概述匿名管道代码示例代码解释运行结果 2. 命名管道命名管道概述命名管道代码示例写入数据的程序&#xff08;writer.cpp&#xff09;读取数据的程序&#xff08;reader.cpp&#xff09; 代码解释运行步骤运行结果 匿名管道…

遇到软件测试职业瓶颈,如何突破

作为职场人&#xff0c;遇到发展瓶颈是在所难免的&#xff0c;无论是晋升受限、技能升级缓慢&#xff0c;还是工作激情的丢失&#xff0c;这些挑战都可能让人感到挫败。但是&#xff0c;积极应对&#xff0c;你就可能找到那扇通向新机遇的窗。 1. 自我评估 识别问题 是缺乏技能…

2024年四川省三支一扶报名流程图解✅

2024年四川省三支一扶报名流程图解✅ &#x1f534;时间安排 1、报名时间&#xff1a;5月31日—6月4日17:00 2、资格初审时间&#xff1a;5月31日—6月5日17:00 3、准考证打印时间&#xff1a;6月25日—6月29日 4、笔试时间&#xff1a;6月30日 5、笔试成绩&#xff1a;7…

电脑显示由于找不到msvcr110.dll 无法继续执行如何处理?最简单的修复msvcr110.dll文件方法

电脑显示由于找不到msvcr110.dll 无法继续执行&#xff1f;当你看到这种提示的时候&#xff0c;请不要紧张&#xff0c;这种是属于dll文件丢失&#xff0c;解决起来还是比较简单的&#xff0c;下面会详细的列明多种找不到msvcr110.dll的解决方法。 一.找不到msvcr110.dll是怎么…

【credit_based流控机制】

credit_based流控机制 1 credit_based way1.1 Principle1.3 DFD1.4 Module1.4.1 Interface1.4.2 Code Block 在网络芯片处理大流量报文中&#xff0c;一般主要是两种机制&#xff1a;1.valid–ready反压(backpressure)机制&#xff1b;2.credit信用机制&#xff1b; credit机制…

idea、datagrip注册记录下

一、DataGrip注册 DataGrip版本号&#xff1a;DataGrip 2023.2 访问地址&#xff1a;https://3.jetbra.in/ 点击“hardbin.com”&#xff0c;下载“jetbra.zip” 在vm里面添加上&#xff1a; -javaagent:D:\work\idea\jetbra\ja-netfilter.jarjetbrains重启datagrip 在刚刚…

自然语言处理(NLP)中的迁移学习

Transfer Learning in NLP 迁移学习&#xff08;Transfer Learning&#xff09;无疑是目前深度学习中的新热点&#xff08;相对而言&#xff09;。在计算机视觉领域&#xff0c;它已经应用了一段时间&#xff0c;人们使用经过训练的模型从庞大的ImageNet数据集中学习特征&…

英飞凌24GHz毫米波雷达-BGT24LTR11N16家用机器人应用

BGT24LTR11N16基础描述&#xff1a; 关于BGT24LTR11N16&#xff0c;它是一款用于信号生成和接收的硅锗雷达MMlC&#xff0c;工作频率为24.00GHz至24.25GHz ISM频段。它基于24GHz基本电压控制振荡器&#xff08;VCO&#xff09;。 这颗芯片是属于1T1R&#xff0c;也就是一发一收…

真实机安装完Centos7没有网卡驱动,ifconfig后,只有lo

文章目录 前言一、1查看网卡型号2 下载相应的驱动程序3、参考官方说明 二、总结 前言 参考1 参考2](https://blog.csdn.net/weixin_46945904/article/details/136365222?spm1001.2101.3001.6650.2&utm_mediumdistribute.pc_relevant.none-task-blog-2defaultYuanLiJiHuaP…

检索字符串

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中&#xff0c;字符串对象提供了很多应用于字符串查找的方法&#xff0c;这里主要介绍以下几种方法。 &#xff08;1&#xff09;count()方…

【busybox记录】【shell指令】rmdir

目录 内容来源&#xff1a; 【GUN】【rmdir】指令介绍 【busybox】【rmdir】指令介绍 【linux】【rmdir】指令介绍 使用示例&#xff1a; 删除空目录 - 默认 删除dirname下的所有空目录&#xff0c;包括因删除其他目录而变为空的目录 常用组合指令&#xff1a; 指令不…

多激光雷达ip与端口配置

首先是雷达的ip 我们连上雷达&#xff0c;想要进入雷达的上位机的时候&#xff0c;需要对本机ip进行一些配置&#xff1a; 第一个是ip&#xff0c;第二个是掩码&#xff0c;第三个是网关。 其中ip可以通过wireshark来进行读取&#xff0c;一般就是192.168.102(雷达默认) 然后掩…

Selenium中使用的三种等待

文章目录 1.前言2.在selenium中常见的等待操作一般有3个 1.前言 在使用selenium时很多元素在使用的时候都需要加载&#xff0c;如果不等待加载结束直接使用就会报错&#xff0c;功能不能继续。一般解决的办法就是使用等待操作。 2.在selenium中常见的等待操作一般有3个 slee…

自定义数据集上的3D目标检测:使用OpenPCDet训练CenterPointPillar模型

前言 在自动驾驶和机器人领域&#xff0c;3D目标检测是关键技术之一。它能够提供关于周围环境中物体的精确位置和尺寸信息。OpenPCDet是一个基于PyTorch的开源3D目标检测框架&#xff0c;支持多种3D检测网络。在本文中&#xff0c;我们将探讨如何使用OpenPCDet框架和CenterPoi…

springboot3 controller中的参数 本地开发可以正常注入,但是打包到生产后就无法识别,必须使用@RequestParam后才可以识别问题解决

问题 在Controller代码中声明了一个参数&#xff0c;本地可以正常注入&#xff1a; RestController public class TestController {GetMapping("test")public String test(String testParam) {return "test" testParam;} }在本地 访问 GET http://local…

树莓派4B 学习笔记1:TF卡系统盘烧录_初次启动_远程端连接配置

今日开始学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; TF卡系统盘烧录_初次启动_远程端连接配置 目录 格式化SD卡&#xff1a; 烧录系统Win32DiskImager&#xff1a; Raspberry Pi Imager镜像烧写&#xff1a; 树莓派官网资料…

浅谈traceroute网络诊断工具

traceroute 是一个网络诊断工具&#xff0c;用于跟踪和显示数据包从源主机到目标主机所经过的每一跳&#xff08;路由器&#xff09;的路径。它能够帮助用户识别网络路径中的瓶颈和故障点。traceroute 的工作原理主要基于 ICMP&#xff08;Internet Control Message Protocol&a…

合约之间调用-如何实现函数静态调用?

合约之间的函数调用 EOA&#xff0c;external owned account&#xff0c;外部账号&#xff0c;例如metamask调用最终总是由EOA发起的合约之间的调用使得一次完整的调用成为一个调用链条 合约间调用过程 调用者须持有被调用合约的地址得到被调用合约的信息将地址重载为被调用合…

NAS搭建自己的Git私服

去年公司采购了一台NAS设备&#xff0c;本来是给文化业务部门做素材库用的&#xff0c;结果我发现磁盘利用率很低&#xff0c;看着那么贵的希捷酷狼闲置真心痛啊&#xff01;突然想到目前公司软件研发的源码管理分两块&#xff0c;一个是gitee&#xff0c;一个是阿里云ECS服务器…