100天精通Golang(基础入门篇)——第20天:Golang 接口 深度解析☞从基础到高级

news2024/12/24 21:33:02

在这里插入图片描述


🌷🍁 博主猫头虎🐅🐾 带您进入 Golang 语言的新世界✨✨🍁
🦄 博客首页——🐅🐾猫头虎的博客🎐
🐳 《面试题大全专栏》 🦕 文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍专栏》 🐾 学会IDEA常用操作,工作效率翻倍~💐
🌊 《100天精通Golang(基础入门篇)》 🐅 学会Golang语言,畅游云原生领域,无厂不可去~💐

🪁🍁 希望本文能给您带来价值🌸如果有任何不足,欢迎批评指正!🐅🐾🍁🐥


100天精通Golang(基础入门篇)

  • 100天精通Golang(基础入门篇)——第20天:接口
      • 摘要
      • 导语
      • 引言
      • 1.1 什么是接口?
      • 1.2 接口的定义语法
      • 1.3 interface值
      • 1.4 接口的类型
      • 1.5 接口断言
      • 1.6 接口的组合
      • 1.7 接口的零值和nil
      • 1.8 接口和指针
      • 1.9 接口嵌套和方法冲突
      • 1.10 接口的实用技巧
      • 1.11 错误处理与接口
      • 1.12 测试与接口
      • 总结
      • 参考资料
  • 结语

100天精通Golang(基础入门篇)——第20天:接口

摘要

📝 第二十天来了,继续我们的 “100天精通Golang(基础入门篇)” 旅程!今天的重点是:Golang 接口深度解析☞从基础到高级。本篇将全方位地揭示接口在 Golang 中的重要性,以及如何让你的代码更加模块化、可测试和可维护。🎯

📝 探究 Golang 的接口机制如何使代码更加模块化、可测试和可维护。本文将从接口的定义、使用,到高级特性进行全面剖析。

导语

👋 大家好,我是猫头虎!今天我们将一同进入 Golang 的神秘花园,探寻接口(Interface)的无穷魅力。如果你对如何有效地使用 Golang 的接口机制感到好奇,那么这篇文章一定适合你。🌟

引言

🎙 在面向对象编程中,接口是一个非常重要的概念。但在 Golang 中,接口不仅用于描述对象的行为,还有许多高级的用途和特性。这使得 Golang 在类型系统的设计上显得非常独特和灵活。接口可以用于多态、代码解耦、错误处理等多个方面,其强大的功能和灵活性使得它成为 Golang 不可或缺的一部分。🛠

1.1 什么是接口?

面向对象世界中的接口的一般定义是“接口定义对象的行为”。它表示让指定对象应该做什么。实现这种行为的方法(实现细节)是针对对象的。

在Go中,接口是一组方法签名。当类型为接口中的所有方法提供定义时,它被称为实现接口。它与OOP非常相似。接口指定了类型应该具有的方法,类型决定了如何实现这些方法。

它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口

接口定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了该接口。

1.2 接口的定义语法

定义接口

/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定义结构体 */
type struct_name struct {
   /* variables */
}

/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* 方法实现*/
}

示例代码:

package main

import (
    "fmt"
)

type Phone interface {
    call()
}

type NokiaPhone struct {
}

func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

func (iPhone IPhone) call() {
    fmt.Println("I am iPhone, I can call you!")
}

func main() {
    var phone Phone

    phone = new(NokiaPhone)
    phone.call()

    phone = new(IPhone)
    phone.call()

}

运行结果:

I am Nokia, I can call you!
I am iPhone, I can call you!
  • interface可以被任意的对象实现
  • 一个对象可以实现任意多个interface
  • 任意的类型都实现了空interface(我们这样定义:interface{}),也就是包含0个method的interface

1.3 interface值

package main

import "fmt"

type Human struct {
	name  string
	age   int
	phone string
}
type Student struct {
	Human  //匿名字段
	school string
	loan   float32
}
type Employee struct {
	Human   //匿名字段
	company string
	money   float32
} //Human实现Sayhi方法
func (h Human) SayHi() {
	fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} //Human实现Sing方法
func (h Human) Sing(lyrics string) {
	fmt.Println("La la la la...", lyrics)
} //Employee重写Human的SayHi方法
func (e Employee) SayHi() {
	fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
		e.company, e.phone) //Yes you can split into 2 lines here.
}

// Interface Men被Human,Student和Employee实现
// 因为这三个类型都实现了这两个方法
type Men interface {
	SayHi()
	Sing(lyrics string)
}

func main() {
	mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
	paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
	sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
	Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
	//定义Men类型的变量i
	var i Men
	//i能存储Student
	i = mike
	fmt.Println("This is Mike, a Student:")
	i.SayHi()
	i.Sing("November rain")
	//i也能存储Employee
	i = Tom
	fmt.Println("This is Tom, an Employee:")
	i.SayHi()
	i.Sing("Born to be wild")
	//定义了slice Men
	fmt.Println("Let's use a slice of Men and see what happens")
	x := make([]Men, 3)
	//T这三个都是不同类型的元素,但是他们实现了interface同一个接口
	x[0], x[1], x[2] = paul, sam, mike
	for _, value := range x {
		value.SayHi()
	}
}

运行结果:

	This is Mike, a Student:
	Hi, I am Mike you can call me on 222-222-XXX
	La la la la... November rain
	This is Tom, an Employee:
	Hi, I am Sam, I work at Things Ltd.. Call me on 444-222-XXX
	La la la la... Born to be wild
	Let's use a slice of Men and see what happens
	Hi, I am Paul you can call me on 111-222-XXX
	Hi, I am Sam, I work at Golang Inc.. Call me on 444-222-XXX
	Hi, I am Mike you can call me on 222-222-XXX

那么interface里面到底能存什么值呢?如果我们定义了一个interface的变量,那么这个变量里面可以存实现这个interface的任意类型的对象。例如上面例子中,我们定义了一个Men interface类型的变量m,那么m里面可以存Human、Student或者Employee值

当然,使用指针的方式,也是可以的

但是,接口对象不能调用实现对象的属性

interface函数参数

interface的变量可以持有任意实现该interface类型的对象,这给我们编写函数(包括method)提供了一些额外的思考,我们是不是可以通过定义interface参数,让函数接受各种类型的参数

嵌入interface

package main

import "fmt"

type Human interface {
	Len()
}
type Student interface {
	Human
}

type Test struct {
}

func (h *Test) Len() {
	fmt.Println("成功")
}
func main() {
	var s Student
	s = new(Test)
	s.Len()
}

示例代码:

package test

import (
	"fmt"
)

type Controller struct {
	M int32
}

type Something interface {
	Get()
	Post()
}

func (c *Controller) Get() {
	fmt.Print("GET")
}

func (c *Controller) Post() {
	fmt.Print("POST")
}
package main

import (
	"fmt"
	"test"
)

type T struct {
	test.Controller
}

func (t *T) Get() {
	//new(test.Controller).Get()
	fmt.Print("T")
}
func (t *T) Post() {
	fmt.Print("T")
}
func main() {
	var something test.Something
	something = new(T)
	var t T
	t.M = 1
	//	t.Controller.M = 1
	something.Get()
}

Controller实现了所有的Something接口方法,当结构体T中调用Controller结构体的时候,T就相当于Java中的继承,T继承了Controller,因此,T可以不用重写所有的Something接口中的方法,因为父构造器已经实现了接口。

如果Controller没有实现Something接口方法,则T要调用Something中方法,就要实现其所有方法。

如果something = new(test.Controller)则调用的是Controller中的Get方法。

T可以使用Controller结构体中定义的变量

1.4 接口的类型

接口与鸭子类型:

先直接来看维基百科里的定义:

If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

翻译过来就是:如果某个东西长得像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那它就可以被看成是一只鸭子。

Duck Typing,鸭子类型,是动态编程语言的一种对象推断策略,它更关注对象能如何被使用,而不是对象的类型本身。Go 语言作为一门静态语言,它通过通过接口的方式完美支持鸭子类型。

而在静态语言如 Java, C++ 中,必须要显示地声明实现了某个接口,之后,才能用在任何需要这个接口的地方。如果你在程序中调用某个数,却传入了一个根本就没有实现另一个的类型,那在编译阶段就不会通过。这也是静态语言比动态语言更安全的原因。

动态语言和静态语言的差别在此就有所体现。静态语言在编译期间就能发现类型不匹配的错误,不像动态语言,必须要运行到那一行代码才会报错。当然,静态语言要求程序员在编码阶段就要按照规定来编写程序,为每个变量规定数据类型,这在某种程度上,加大了工作量,也加长了代码量。动态语言则没有这些要求,可以让人更专注在业务上,代码也更短,写起来更快,这一点,写 python 的同学比较清楚。

Go 语言作为一门现代静态语言,是有后发优势的。它引入了动态语言的便利,同时又会进行静态语言的类型检查,写起来是非常 Happy 的。Go 采用了折中的做法:不要求类型显示地声明实现了某个接口,只要实现了相关的方法即可,编译器就能检测到。

总结一下,鸭子类型是一种动态语言的风格,在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由它"当前方法和属性的集合"决定。Go 作为一种静态语言,通过接口实现了鸭子类型,实际上是 Go 的编译器在其中作了隐匿的转换工作。

Go语言的多态性:

Go中的多态性是在接口的帮助下实现的。正如我们已经讨论过的,接口可以在Go中隐式地实现。如果类型为接口中声明的所有方法提供了定义,则实现一个接口。让我们看看在接口的帮助下如何实现多态。

任何定义接口所有方法的类型都被称为隐式地实现该接口。

类型接口的变量可以保存实现接口的任何值。接口的这个属性用于实现Go中的多态性。

1.5 接口断言

前面说过,因为空接口 interface{}没有定义任何函数,因此 Go 中所有类型都实现了空接口。当一个函数的形参是interface{},那么在函数中,需要对形参进行断言,从而得到它的真实类型。

语法格式:

// 安全类型断言

<目标类型的值><布尔参数> := <表达式>.( 目标类型 )

//非安全类型断言

<目标类型的值> := <表达式>.( 目标类型 )

示例代码:

package main

import "fmt"

func main() {

   var i1 interface{} = new (Student)
   s := i1.(Student) //不安全,如果断言失败,会直接panic

   fmt.Println(s)


	var i2 interface{} = new(Student)
	s, ok := i2.(Student) //安全,断言失败,也不会panic,只是ok的值为false
	if ok {
		fmt.Println(s)
	}
}

type Student struct {

}

断言其实还有另一种形式,就是用在利用 switch语句判断接口的类型。每一个case会被顺序地考虑。当命中一个case 时,就会执行 case 中的语句,因此 case 语句的顺序是很重要的,因为很有可能会有多个 case匹配的情况。

示例代码:

switch ins:=s.(type) {
	case Triangle:
		fmt.Println("三角形。。。",ins.a,ins.b,ins.c)
	case Circle:
		fmt.Println("圆形。。。。",ins.radius)
	case int:
		fmt.Println("整型数据。。")
	}

1.6 接口的组合

在 Go 语言中,一个接口可以由多个小接口组合而成。这样的组合方式提供了一种“继承”的感觉,使得接口更加模块化。

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

在这个例子中,ReadWriter 接口组合了 ReaderWriter 接口,一个实现了 ReadWriter 接口的类必须实现所有 ReaderWriter 接口中定义的方法。

1.7 接口的零值和nil

在 Go 中,接口内部有两个组件,一个是具体的类型,另一个是该类型的值。当我们定义一个接口变量时,这两个组件都会初始化为 nil。

var a interface{}
fmt.Printf("%v, %T\n", a, a) // "nil, nil"

当一个接口变量的类型和值都为 nil 时,我们称该变量为 nil 接口变量。

1.8 接口和指针

指针类型和它所指向的值类型是两个不同的类型,因此,如果一个接口类型的方法集合包含使用值接收者定义的方法,那么这个接口可以存储这个指针类型的值。

type Describer interface {
    Describe()
}

type Person struct {
    name string
}

func (p Person) Describe() {
    fmt.Println("I am a person.")
}

func main() {
    var d1 Describer
    p1 := Person{"Sam"}
    d1 = &p1
    d1.Describe()
}

1.9 接口嵌套和方法冲突

接口也可以嵌套接口,但要注意方法不要冲突。

type ReadCloser interface {
    Reader
    Closer
}
type Closer interface {
    Close() error
    //Read() // 这里如果定义Read方法,将与Reader接口冲突
}

1.10 接口的实用技巧

  1. 类型查询: 除了类型断言,你还可以使用 , ok 语法来安全地查询值的类型。

    if val, ok := myVar.(MyType); ok {
        // ...
    }
    
  2. 使用接口收集不同类型的值: 你可以创建接受接口类型参数的函数或方法,以处理不同类型的值。

  3. 使用接口实现模板模式: 通过定义一个接口来封装算法的变化,然后通过具体的类型来实现算法的可替换部分。

1.11 错误处理与接口

Go 语言中的错误处理也是基于接口的。标准库中有一个 error 接口用于处理错误:

type error interface {
    Error() string
}

自定义错误通常会实现这个接口,提供更多的上下文信息和错误处理能力。

1.12 测试与接口

在 Go 中进行单元测试时,接口非常有用。你可以创建模拟对象来代替真实的依赖,这些模拟对象实现了同样的接口。

这样的话,你可以在测试环境下替换这些依赖,使得单元测试更加容易编写和维护。

总结

🔍 通过本文,你应该对 Golang 的接口有了全面且深入的理解。无论是基础的类型实现,还是高级的接口组合和多态性,接口都能让我们的代码更加简洁和高效。掌握接口不仅可以让你更加自如地使用 Golang,也会极大地提升你的编程水平。记住,掌握接口就是走向 Golang 高手之路的关键一步。🔑

接口在 Go 中是一种非常强大和灵活的机制,用于解耦和组织代码。它们提供了一种方式来规范对象行为,允许我们编写可复用和可测试的代码。了解和掌握接口是成为 Go 语言高手的关键之一。

参考资料

📚

  1. Go Programming Language Specification
  2. Effective Go
  3. Go Blog: Interfaces in Go
  4. Go by Example: Interfaces

希望大家喜欢这篇文章!如果你有任何问题或想要进一步探讨,随时在下方留言。👇 不要忘了点赞和分享!👍🚀

在这里插入图片描述

结语

通过今天的学习,您已经踏上了Golang的学习之旅。在未来的日子里,您将探索Golang的各个方面,从基础概念到高级技巧,从实际应用到性能优化。
学习一门编程语言是一个持续的过程,每一天都是您向Golang的精通迈进的重要一步。我鼓励您坚持每天学习,保持热情和好奇心,解决挑战并享受成功的喜悦。

在您的学习旅程中,不要忘记参与社区和与其他Golang开发者交流。分享您的见解和经验,向他人学习,并在开源项目或实际应用中展示您的技能。

如果您在学习过程中遇到困难或有任何问题,不要犹豫向社区和专家寻求帮助。持续学习,勇敢探索,您将在Golang领域取得令人瞩目的成就。

最后,感谢您的阅读和支持!祝愿您在未来的每一天中都能够成为一名精通Golang的开发者!

期待听到您在学习过程中的进展和成就。如果您需要进一步的帮助,请随时告诉我。祝您在学习Golang的旅程中取得巨大成功!

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。

如果您在学习过程中有任何疑惑,请点击下方名片,带您一对一快速入门 Go语言 的世界 ~

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

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

相关文章

FI 数据源(AP) 及 增量逻辑

AP 一般AP里要分析行项目数据&#xff0c;交易数据&#xff0c;历史付款信息。 还有一些供应商主数据。 基础的抽取数据源就是下面几个&#xff1a; 0FI_AP_4: Vendors: Line Items with Delta Extrcation0FI_AP_6: Vendor Sales Figures via Delta Extraction0FI_AP_7: Ve…

SQLPro Studio for Mac:强大的SQL开发和管理工具

SQLPro Studio for Mac是一款强大的Mac上使用的SQL开发和管理工具&#xff0c;它支持各种数据库&#xff0c;包括MySQL&#xff0c;PostgreSQL&#xff0c;SQLite等。使用 SQLPro Studio&#xff0c;您可以轻松地连接和管理您的数据库&#xff0c;执行SQL查询和脚本&#xff0c…

【python爬虫】8.温故而知新

文章目录 前言回顾前路代码实现体验代码功能拆解获取数据解析提取数据存储数据 程序实现与总结 前言 Hello又见面了&#xff01;上一关我们学习了爬虫数据的存储&#xff0c;并成功将QQ音乐周杰伦歌曲信息的数据存储进了csv文件和excel文件。 学到这里&#xff0c;说明你已经…

国标视频融合云平台EasyCVR视频汇聚平台关于远程控制的详细介绍

EasyCVR国标视频融合云平台是一个能在复杂网络环境下统一汇聚、整合和集中管理各类分散视频资源的平台。该平台提供了多种视频能力和服务&#xff0c;包括视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、集群、电子地图、H.265视频自动转码和智能分析等…

一种基于WinDump自动抓包实现方法

本发明的技术方案包括以下步骤和组件&#xff1a; 配置抓包参数&#xff1a;设置抓包的IP、端口以及过滤包大小等参数&#xff0c;以控制抓取的数据范围。循环自动抓包&#xff1a;利用WinDump工具实现循环自动抓包功能&#xff0c;类似于记录日志的方式保留抓包数据。当抓包数…

年收入超10亿美金?OpenAI 的“赚钱戏法”

点击关注 文丨郝鑫、刘雨琦&#xff0c;编丨刘雨琦 “我当时见到他不到三分钟&#xff0c;就在想&#xff0c;啊&#xff0c;19岁的比尔盖茨估计也就这样了吧&#xff01;” 在YC创始人Paul Graham&#xff08;格雷厄姆&#xff09;的眼里&#xff0c;28岁的Sam Altman与19…

香港服务器快还是台湾服务器快?

​  基于机房位置不同&#xff0c;香港服务器相对于台湾服务器在访问速度方面有一定的优势。香港服务器拥有CN2线路&#xff0c;因此访问速度较快。在网络服务商方面&#xff0c;中华电信等台湾服务商提供的带宽也具有很高的性价比。 香港服务器对大陆用户的影响 对于大陆用户…

如何将电子画册生成二维码,扫码查看产品图册?

随着移动互联网的发展&#xff0c;二维码已经成为了人们生活中不可或缺的一部分。无论是支付宝、微信支付的扫码支付&#xff0c;还是商家的促销活动、产品包装上的二维码&#xff0c;都展示了二维码的广泛应用。 电子画册也果不其然&#xff0c;它也可以生成二维码&#xff0c…

高德地图jsapi报错INVALID_USER_SCODE

看了各种网上方法&#xff0c;还是搞不定。无奈在高德开放平台提了工单。 很快高德的技术人员就给出了答复“您好&#xff0c;您检查一下您的安全密钥是否在key之前&#xff0c;安全密钥设置必须是在JS API 脚本加载之前进行设置&#xff0c;否则设置无效。” 并给出了推荐的…

使用 zipfile创建文件压缩工具

在本篇博客中&#xff0c;我们将使用 wxPython 模块创建一个简单的文件压缩工具。该工具具有图形用户界面&#xff08;GUI&#xff09;&#xff0c;可以选择源文件夹中的文件&#xff0c;将其压缩为 ZIP 文件&#xff0c;并将压缩文件保存到目标文件夹中。 C:\pythoncode\new\z…

如何提高工业网关的数据传输速度?

工业网关是工业物联网系统中不可或缺的设备&#xff0c;提高工业网关的数据采集、传输速度&#xff0c;是保障和优化物联网系统运营效率的基础。如何提高工业物联网关的数据传输速度&#xff1f;本篇就为大家简单介绍一下。 1、选用高品质网络设备 选用具有足够带宽容量的高质…

深圳发墨西哥专线要多久才能清关?

深圳发往墨西哥专线的货物清关时间会受到多种因素的影响&#xff0c;包括货物的性质、数量、海关政策、运输方式以及货物的文件准备等。下面将详细介绍这些因素对清关时间的影响。 1.货物的性质和数量是影响清关时间的重要因素之一。 一般来说&#xff0c;墨西哥专线中普通商品…

C语言_分支和循环语句(3)

文章目录 前言一、猜数字游戏1.1.电脑随机生成一个数&#xff08;1~100&#xff09;&#xff1b;1.2.猜数字&#xff1a;1.3.玩完一把不过瘾&#xff0c;可以继续玩&#xff0c;不用退出程序。1.4.rand 和 srand 之间的联系5.猜数字游戏源码 二、go to 语句2.1.例如&#xff1a…

PMP项目管理主要学习内容是什么?

PMP项目管理是指根据美国项目管理学会(Project Management Institute&#xff0c;简称PMI)制定的项目管理知识体系和方法论进行项目管理的一种认证。PMP主要关注项目的规划、执行和控制等方面的知识和技能。 下面是PMP项目管理《PMBOK指南》第六版的主要学习内容&#xff1a; …

RT-内核介绍

内核是一个操作系统的核心&#xff0c;是操作系统最基础也最重要的部分。它负责管理系统的线程、线程间通信、系统时钟、中断及内存等。 下图为 RT-Thread 内核架构图&#xff0c;内核部分包含内核库、实时内核实现。 内核库是为了保证内核能够独立运行的一套小型的类似C库的函…

新款岚图 FREE 26.69 万元,继续修高端操作

新款岚图 FREE 正式上市&#xff0c;新车共有一款车型&#xff0c;超长续航智驾版售价 26.69 万元。 在选装和上市权益方面&#xff0c;新款岚图 FREE 可选装百度 Apollo 高阶智驾选装包&#xff0c;价值 2.5 万元。 在 12 月 31 日前购买新款岚图 FREE &#xff0c;用户可以…

视频监控/视频汇聚/视频云存储EasyCVR平台接入华为ivs3800平台提示400报错,该如何解决?

开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频云存储/安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频…

【高级程序设计语言C++】C++11

1. lambda表达式2. 移动构造函数和移动赋值运算符重载3. default关键字4. delete关键字5. 可变参数模板6. push_back和emplace_back的区别6.1. emplace_back的优势 7. 包装器7.1. 包装器的语法格式 1. lambda表达式 在C中&#xff0c;lambda表达式是一种用于创建匿名函数的语法…

发表于《自然》杂志:语音转文本BCI的新突破实现62字/分钟的速度

语音脑机接口&#xff08;BCI&#xff09;是一项创新技术&#xff0c;通过用户的大脑信号在用户和某些设备之间建立通信通道&#xff0c;它们在恢复残疾患者的言语和通信能力方面具有巨大潜力。 早期的研究虽然很有希望&#xff0c;但尚未达到足够高的精度来解码大脑活动&…

深入MaxCompute -第十弹 -IF ELSE分支语句

简介&#xff1a; MaxCompute通过脚本模式支持IF ELSE分支语句&#xff0c;让程序根据条件自动选择执行逻辑&#xff0c;支持更好的处理因数据不同而需要采用不同策略的业务场景产生的复杂SQL&#xff0c;提高开发者编程的灵活性&#xff01; MaxCompute&#xff08;原ODPS&am…