1. 静态语言(强类型语言)
静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。
例如:C++、Java、Delphi、C#等。
2. 动态语言(弱类型语言)
动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是是由值的类型决定的。
例如PHP、ASP、Ruby、Python、Perl、ABAP、SQL、JavaScript、Unix Shell等等。
3. 强类型定义语言
强制数据类型定义的语言。也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。
举个例子:如果你定义了一个整型变量a,那么程序根本不可能将a当作字符串类型处理。强类型定义语言是类型安全的语言。
4. 弱类型定义语言
5. 两者区别
特性
强类型语言是一旦变量的类型被确定,就不能转化的语言。
弱类型语言则反之,一个变量的类型是由其应用上下文确定的。
静态语言的优势
由于类型的强制声明,使得IDE有很强的代码感知能力,故,在实现复杂的业务逻辑、开发大型商业系统、以及那些生命周期
很长的应用中,依托IDE对系统的开发很有保障;
由于静态语言相对比较封闭,使得第三方开发包对代码的侵害性可以降到最低;
动态语言的优势
思维不受束缚,可以任意发挥,把更多的精力放在产品本身上;
集中思考业务逻辑实现,思考过程即实现过程;
duck typing(鸭子类型)字面解释是 如果一只动物走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只动物就可以被称为鸭子
所谓的 Duck Typing,它只关心事物的外部行为而非内部结构。
就如只关系一个动物走路、游泳、叫声是否像gv,如果像则认为是鸭子。它并不关心你这只鸭子内部构造是长肉的还是充气的,仅仅通过外部行为。
许多编程语言都支持 Duck Typing ,通常 Duck Typing 是动态编程语言用来实现多态的一种方式。
1. Python中的duck typing
例如
def download(retriever):
return retriever.get("http://xxx")
有一个 download 函数,传过来一个 retriever参数,retriever是可以获取一个 url 链接的资源的。这个 fetcher 就是一个 Duck Typing 的对象,使用者约定好这个 retriever 会有一个 get 函数就可以了;
Python是动态语言,retriever随便什么类型都可以,只要实现一个 get 方法,就能通过编译;
但是会出现以下情况:
运行时才知道传入的 retriever 有没有 get 函数;
需要注释来说明接口。从 download 函数的使用者的角度上看,我怎么知道需要给 retriever 实现 get 方法呢?我不可能去阅读 download 函数的代码,实际情况中,可能 download 函数的代码很长,可能 retriever不只要实现 get 方法,还有其它方法需要实现。通常这种情况需要通过加注释来说明。
2. C++中的 duck typing
例如
template <class R>
string download(const R& retriever) {
return retriever.get("http://xxx")
}
C++ 是静态语言,但是它也能支持 Duck Typing,它是通过模板来支持的;
C++通过模板达到 retriever 随便什么类型都可以,只要实现一个 get 方法,就能通过编译的目的;
但是会出现以下情况:
编译时,才知道传入的 fetcher 有没有 get 这个方法。相比Python 运行时 才知道有没有get方法,好了一些。
同样,还是需要注释来说明
3. Java中的类似代码
<R extends Retriever>
String download(R r) {
return r.get("http://xxx")
}
同样也用了模板类型。模板 F 必须 extends Retriever ,有了这个限定,就能逼着 download 函数的使用者对 r 实现 get 方法,它解决了需要注释来说明的缺点;
传入的参数必须实现 Retriever 接口,Retriever中存在get()方法,就没有运行时发现错误,编译时发现错误的问题;
但是,它严格上来说不是 Duck Typing,因为传的参数必须实现 Retriever 接口,即便定义一个实现get方法的其他接口,他也不能作为参数传入 ;
如果 download 函数只依赖 r 的 get 方法,而 Retrieve 接口必须要实现除 get 方法以外,还有其它方法,那么也要一一实现,非常不灵活。
4. Golang中的duck typing
在 Java 的 Duck Typing 类似代码中,如果 r 参数需要同时实现两个或以上的接口方法时,Java 是没有办法做到的。但 Go 语言可以做到;
Go具有Python、C++的duck typing的灵活性,什么类型都能作为参数;
有具有java的类型检查,不需要通过注释说明;
package main
import (
"fmt"
)
type Retriever interface { // 定义接口Retriever
Get(url string) string
isDelete() bool
}
// 定义结构体
type RandomName struct {
context string
isEmpty bool
}
// 实现接口Retriever的所有方法,让结构体Random实现接口Retriever
func (rn RandomName) Get(url string) string{
return rn.context + url
}
func (rn RandomName) isDelete() bool{
rn.context = ""
rn.isEmpty = false
return rn.isEmpty
}
// 定义两个普通函数,体验Go中的duck typing
func download(r Retriever) string{ // Retriever是一个接口
return r.Get("www.baidu.com") //使用者 使用Get()方法
}
func clean(r Retriever) bool{
return r.isDelete()
}
func main() {
var r Retriever // 定义变量rn为接口Retriever类型,这里r是接口指针类型
r = RandomName{"this is a web about ", true} // 结构体RandomName实现接口Retriever
fmt.Println(download(r))
// r是结构体RnadomName,download接受的参数是Retriever接口。
// 因为结构体RandomName实现接口Retriever故传参为RandomName接口也行
// duck typing的体现。
fmt.Println(clean(r))
}
this is a web about www.baidu.com
false
package main
import (
"fmt"
)
// 接口
type Retriever interface { // 定义接口Retriever
Get(url string) string
isDelete() bool
}
// 结构体1
type RandomName1 struct {
context string
isEmpty bool
}
func (rn *RandomName1) Get(url string) string{
return rn.context + url
}
func (rn *RandomName1) isDelete() bool{
rn.context = ""
rn.isEmpty = false
return rn.isEmpty
}
// 结构体二
type RandomName2 struct {
context string
isEmpty bool
}
func (rn RandomName2) Get(url string) string{
return rn.context + url
}
func (rn RandomName2) isDelete() bool{
rn.context = ""
rn.isEmpty = false
return rn.isEmpty
}
func inspect(r Retriever) {
fmt.Printf("%T %v\n", r, r)
switch v := r.(type) {
case *RandomName1:
fmt.Println("Contents:", v.context)
fmt.Println("isEmpty", v.isEmpty)
case RandomName2:
fmt.Println("Contents:", v.context)
fmt.Println("isEmpty", v.isEmpty)
}
}
func main() {
var r Retriever // 接口变量
// RandomName1中方法Get、isDelete是指针接收者,故指针变量r只能以指针方式使用
r = &RandomName1{
context: "this is a web about ",
isEmpty: true}
inspect(r)
// Type assertion
name1 := r.(*RandomName1)
fmt.Println(name1.isEmpty)
fmt.Println("---------------------")
// RandomName2中方法Get、isDelete是值接收者,故指针变量r可以使用指针方式或者不使用
r = RandomName2{
context: "",
isEmpty: false,
}
//r = &RandomName2{ // 指针方式也没报错
// context: "",
// isEmpty: false,
//}
inspect(r)
// Type assertion
if name2, ok := r.(RandomName2); ok {
fmt.Println(name2.isEmpty)
} else {
fmt.Println("this is not RnadomName2 Retriever!")
}
}
*main.RandomName1 &{this is a web about true}
Contents: this is a web about
isEmpty true
true
---------------------
main.RandomName2 { false}
Contents:
isEmpty false
false
package main
import "fmt"
// 接口一
type Retriever interface{
Get(url string) string
}
// 接口二
type Poster interface {
Post(url string,
form map[string]string) string
}
// 接口组合
type Association interface { // 将多个接口组合一起
Retriever
Poster
OtherMethod(other string)
}
// Association接口的实现,结构体
type AssociationStruct struct {
Contents string
}
func (a *AssociationStruct) Post(url string,
form map[string]string) string {
a.Contents = form["contents"]
return "ok"
} // 以上AssociationStruct结构体实现接口Poster
func (a *AssociationStruct) Get(url string) string{
return a.Contents
} // 以上AssociationStruct结构体实现接口Retriever
func (a *AssociationStruct) OtherMethod(other string) {
fmt.Println("other method!")
} // 以上AssociationStruct结构体实现接口Association
// 其他函数
const url string = "http://www.imooc.com"
// 修改参数contents的值
func assiociation(a Association) string{
a.Post(url, map[string]string {
"contents" : "another faked imooc.com",
}) // 调用已实现接口的方法,修改contents值
return a.Get(url)
}
func main() {
var a Association // 接口变量
a = &AssociationStruct{"this is a fake imooc.com"}
fmt.Println(assiociation(a))
}
another faked imooc.com
接口Stringer
系统中接口定义
type Stringer interface {
String() string
}
接口Reader
系统中接口定义
type Reader interface {
Read(p []byte) (n int, err error) // 可以从文件中读取数据
}
接口Writer
系统中接口定义
type Writer interface {
Write(p []byte) (n int, err error) // 可以写数据到文件中
}
package main
import (
"fmt"
)
type Retriever interface {
Get(url string) string
}
type Association interface {
Retriever
fmt.Stringer
}
// 结构体RetrieverStruct实现接口Retriever和接口Stringer
type RetrieverStruct struct {
Contents string
}
func (r *RetrieverStruct) Get(url string) string { // 实现接口Retriever
return r.Contents
}
func (r *RetrieverStruct) String() string{ // 实现接口Stringer
return fmt.Sprintf(
"Retriever : {Contents = %s}", r.Contents)
}
func main() {
var a Association
a = &RetrieverStruct{"this is a fake imooc.com"}
fmt.Println(a.String())
}
Retriever : {Contents = this is a fake imooc.com}
静态语言和动态语言的区别
编程语言中的 DUCK TYPING