Golang中Interface類型詳解

本文章翻譯自《Let's learn Go》的“Interfaces: the awesomesauce of Go”一節(jié),原文地址:http://go-book.appspot.com/interfaces.html

讓我們重新梳理一下以前的內(nèi)容。我們了解了基本的數(shù)據(jù)類型,我們學(xué)習(xí)了如何利用已有的數(shù)據(jù)類型構(gòu)造出一個(gè)新的數(shù)據(jù)類型。我們學(xué)習(xí)了基本的控制流語(yǔ)句,我們將要結(jié)合這些知識(shí)構(gòu)建一些簡(jiǎn)單的應(yīng)用程序。

接下來(lái)我們會(huì)發(fā)現(xiàn)函數(shù)實(shí)際上也是一種數(shù)據(jù),他們具有自己的值和類型。我們將要學(xué)習(xí)關(guān)于方法的基本知識(shí)。我們使用方法來(lái)構(gòu)建作用于數(shù)據(jù)上的函數(shù),從而使某個(gè)數(shù)據(jù)類型完成特定的功能。

在本章中,將要學(xué)習(xí)一個(gè)新的領(lǐng)域。我們將學(xué)習(xí)使用面向?qū)ο缶幊痰撵`魂去構(gòu)建程序,讓我們一起做這件事吧。

What is an interface?

簡(jiǎn)單的說(shuō),接口就是一組方法簽名的集合。我們使用一個(gè)接口來(lái)識(shí)別一個(gè)對(duì)象的能夠進(jìn)行的操作。

舉例來(lái)說(shuō),在以前的章節(jié)中,我們看到Student和Emlpoyee都可以執(zhí)行SayHi函數(shù),但是他們的運(yùn)行結(jié)構(gòu)是不同的,但是這個(gè)是無(wú)關(guān)緊要的,本質(zhì)是他們都可以說(shuō)“Hi”(這部分下邊的內(nèi)容會(huì)有體現(xiàn))。

我們假設(shè)Student和Employee實(shí)現(xiàn)了另外一個(gè)共同的函數(shù)Sing。Employ實(shí)現(xiàn)了SpendSalary函數(shù),與此相對(duì)應(yīng)Student實(shí)現(xiàn)了BorrowMoney函數(shù)。

所以Student實(shí)現(xiàn)了SayHi、Sing和BorrowMoney函數(shù),Employee實(shí)現(xiàn)了SayHi、Sing和SpendSalary函數(shù)。

這些方法的集合就是Student和Employee滿足的接口類型。舉例來(lái)說(shuō),Student和Employee都滿足包含SayHi和Sing方法簽名的接口。但是Employee不能滿足包含SayHi、Sing和BorrowMoney的接口類型,因?yàn)镋mployee沒有實(shí)現(xiàn)方法BorrowMoney。

The interface type

接口類型實(shí)際上是一組方法簽名的清單,我們將遵循下面的接口約束:

type Human struct {
    name string
    age int
    phone string
}

type Student struct {
    Human //an anonymous field of type Human
    school string
    loan float32
}

type Employee struct {
    Human //an anonymous field of type Human
    company string
    money float32
}

// A human likes to stay... err... *say* hi
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

// A human can sing a song, preferrably to a familiar tune!
func (h *Human) Sing(lyrics string) {
    fmt.Println("La la, la la la, la la la la la...", lyrics)
}

// A Human man likes to guzzle his beer!
func (h *Human) Guzzle(beerStein string) {
    fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}

// Employee's method for saying hi overrides a normal Human's one
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.
}

// A Student borrows some money
func (s *Student) BorrowMoney(amount float32) {
    loan += amount // (again and again and...)
}

// An Employee spends some of his salary
func (e *Employee) SpendSalary(amount float32) {
    e.money -= amount // More vodka please!!! Get me through the day!
}

// INTERFACES
type Men interface {
    SayHi()
    Sing(lyrics string)
    Guzzle(beerStein string)
}

type YoungChap interface {
    SayHi()
    Sing(song string)
    BorrowMoney(amount float32)
}

type ElderlyGent interface {
    SayHi()
    Sing(song string)
    SpendSalary(amount float32)
}

正如你所看到的那樣,一個(gè)接口可以被任意數(shù)量的類型滿足,在這里Student和Employee都實(shí)現(xiàn)了Men接口。

并且,一個(gè)類型可以實(shí)現(xiàn)任意數(shù)量的接口,在這里,Student實(shí)現(xiàn)了Men和YoungChap接口,Employee實(shí)現(xiàn)了Men和ElderlyGent接口。

最后需要說(shuō)明的是,每個(gè)類型都實(shí)現(xiàn)了一個(gè)空接口interface{},大概你要說(shuō),這意味著該類型沒有方法,我們重新聲明一下interface{}的意義。

你可能自以為發(fā)現(xiàn)接口類型的意義:
非常酷,接口類型的意義就是描述數(shù)據(jù)類型的行為,以及數(shù)據(jù)類型的共性特征

然而事實(shí)上,接口類型的意義遠(yuǎn)遠(yuǎn)不止于此。

順便說(shuō)一下,我說(shuō)過(guò)空接口意味著不包含方法簽名嗎?

Interface values

因?yàn)榻涌谝彩且环N類型,你會(huì)困惑于一個(gè)接口類型的值到底是什么。

有一個(gè)好消息就是:如果你聲明了一個(gè)接口變量,這個(gè)變量能夠存儲(chǔ)任何實(shí)現(xiàn)該接口的對(duì)象類型。

也就是說(shuō),如果我們聲明了Men類型的接口變量m,那么這個(gè)變量就可以存儲(chǔ)Student和Employee類型的對(duì)象,還有Human類型(差點(diǎn)忘掉)。這是因?yàn)樗麄兌紝?shí)現(xiàn)了Men接口聲明的方法簽名。

如果m能夠存儲(chǔ)不同數(shù)據(jù)類型的值,我們可以輕松實(shí)現(xiàn)一個(gè)Men切片,該切片包含不同的數(shù)據(jù)類型的實(shí)例。

下面這個(gè)例子能夠幫助梳理我們上面的說(shuō)教:

package main
import "fmt"

type Human struct {
    name string
    age int
    phone string
}

type Student struct {
    Human //an anonymous field of type Human
    school string
    loan float32
}

type Employee struct {
    Human //an anonymous field of type Human
    company string
    money float32
}

//A human method to say hi
func (h Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

//A human can sing a song
func (h Human) Sing(lyrics string) {
    fmt.Println("La la la la...", lyrics)
}

//Employee's method overrides Human's one
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 is implemented by Human, Student and Employee
// because it contains methods implemented by them.
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}

    //a variable of the interface type Men
    var i Men

    //i can store a Student
    i = mike
    fmt.Println("This is Mike, a Student:")
    i.SayHi()
    i.Sing("November rain")

    //i can store an Employee too
    i = Tom
    fmt.Println("This is Tom, an Employee:")
    i.SayHi()
    i.Sing("Born to be wild")

    //a slice of Men
    fmt.Println("Let's use a slice of Men and see what happens")
    x := make([]Men, 3)
    //These elements are of different types that satisfy the Men 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

你可能已經(jīng)注意到,接口類型是一組抽象的方法集,他本身并不實(shí)現(xiàn)方法或者精確描述數(shù)據(jù)結(jié)構(gòu)和方法的實(shí)現(xiàn)方式。接口類型只是說(shuō):“兄弟,我實(shí)現(xiàn)了這些方法,我能勝任”。

值得注意的是這些數(shù)據(jù)類型沒有提及任何的關(guān)于接口的信息(我的理解是Student和Employee數(shù)據(jù)類型),方法簽名的實(shí)現(xiàn)部分也沒有包含給定的接口類型的信息。

同樣的,一個(gè)接口類型也不會(huì)去關(guān)心到底是什么數(shù)據(jù)類型實(shí)現(xiàn)了他自身,看看Men接口沒有涉及Student和Employee的信息就明白了。接口類型的本質(zhì)就是如果一個(gè)數(shù)據(jù)類型實(shí)現(xiàn)了自身的方法集,那么該接口類型變量就能夠引用該數(shù)據(jù)類型的值。

The case of the empty interface

空接口類型interface{}一個(gè)方法簽名也不包含,所以所有的數(shù)據(jù)類型都實(shí)現(xiàn)了該方法

空接口類型在描述一個(gè)對(duì)象實(shí)例的行為上力不從心,但是當(dāng)我們需要存儲(chǔ)任意數(shù)據(jù)類型的實(shí)例的時(shí)候,空接口類型的使用使得我們得心應(yīng)手。

// a is an empty interface variable
var a interface{}
var i int = 5
s := "Hello world"
// These are legal statements
a = i
a = s

如果一個(gè)函數(shù)的參數(shù)包括空接口類型interface{},實(shí)際上函數(shù)是在說(shuō)“兄弟,我接受任何數(shù)據(jù)”。如果一個(gè)函數(shù)返回一個(gè)空接口類型,那么函數(shù)再說(shuō)“我也不確定返回什么,你只要知道我一定返回一個(gè)值就好了”。

是不是很有用處?請(qǐng)接著看。

Functions with interface parameters

以上的例子給我們展示了一個(gè)接口類型如何存儲(chǔ)滿足他的的數(shù)據(jù)類型實(shí)例,并且展示給我們?nèi)绾蝿?chuàng)建存儲(chǔ)不同數(shù)據(jù)類型實(shí)例的集合。

利用此思想,我們還可以讓函數(shù)來(lái)接受滿足特定接口類型的數(shù)據(jù)類型實(shí)例。

舉例來(lái)說(shuō),我們已經(jīng)知道fmt.Print 是一個(gè)可變參數(shù)的函數(shù),他可以接受任意數(shù)量的參數(shù)。但是你有沒有注意到,有時(shí)候我們使用的是strings、ints和floats?

事實(shí)上,如果你深入去看fmt包,你就會(huì)看到如下的接口聲明:

//The Stringer interface found in fmt package
type Stringer interface {
     String() string
}

任何數(shù)據(jù)類型,只要實(shí)現(xiàn)了Stringer接口,就能夠傳遞給fmt.Print函數(shù),然后打印出該類型String()函數(shù)的返回值。

讓我們?cè)囈幌拢?/p>

package main
import (
    "fmt"
    "strconv" //for conversions to and from string
)

type Human struct {
    name string
    age int
    phone string
}

//Returns a nice string representing a Human
//With this method, Human implements fmt.Stringer
func (h Human) String() string {
    //We called strconv.Itoa on h.age to make a string out of it.
    //Also, thank you, UNICODE!
    return "?"+h.name+" - "+strconv.Itoa(h.age)+" years -  ? " +h.phone+"?"
}

func main() {
    Bob := Human{"Bob", 39, "000-7777-XXX"}
    fmt.Println("This Human is : ", Bob)
}

輸出是

This Human is : ?Bob - 39 years - ? 000-7777-XXX?

現(xiàn)在回頭看一下我們?cè)趺词褂胒mt.Print,我們傳遞給他參數(shù)Bob,Bob是一個(gè)Human類型的實(shí)例,然后Bob就被優(yōu)雅的打印出來(lái)。我們所做的就是是Human實(shí)現(xiàn)了String()方法。

回想一下colored boxes example的例子(這是以前章節(jié)的,但是這里我認(rèn)為不會(huì)影響大家的理解)?我們有一個(gè)Color類型,這個(gè)類型實(shí)現(xiàn)了String方法。我們重新回到那個(gè)程序,然后調(diào)用fmt.Print函數(shù)來(lái)打印結(jié)果:

//These two lines do the same thing
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("The biggest one is", boxes.BiggestsColor())

是不是很酷?

另外一個(gè)讓你喜歡上interface接口的例子就是sort包,這個(gè)包用來(lái)對(duì)int、float和string數(shù)據(jù)類型進(jìn)行排序。

我們先看一個(gè)小例子,然后給你展示一個(gè)這個(gè)包的神奇之處。

``package main
import(
"fmt"
"sort"
)

func main() {
// list is a slice of ints. It is unsorted as you can see
list := []int {1, 23, 65, 11, 0, 3, 233, 88, 99}
fmt.Println("The list is: ", list)

// let's use Ints function that comes in sort
// Ints([]int) sorts its parameter in ibcreasing order. Go read its doc.
sort.Ints(list)
fmt.Println("The sorted list is: ", list)

}

輸出:

The list is: [1 23 65 11 0 3 233 88 99]
The sorted list is: [0 1 3 11 23 65 88 99 233]

是不是很簡(jiǎn)單的工作,但是我想展示的更加吸引人。
事實(shí)上,sort包定義了一個(gè)包含三個(gè)方法簽名的接口類型:

``
type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less returns whether the element with index i should sort
    // before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

在sort接口的文檔中我們可以看到:

type, typically a collection, that satisfies sort. Interface can be sorted by the routines in this package. The methods require that the elements of the collection be enumerated by an integer index.

所以我們?yōu)榱伺判蛞粋€(gè)給定的切片只需要實(shí)現(xiàn)這三個(gè)函數(shù)就可以了!我們來(lái)試一下吧:

package main
import (
    "fmt"
    "strconv"
    "sort"
)

type Human struct {
    name string
    age int
    phone string
}

func (h Human) String() string {
    return "(name: " + h.name + " - age: "+strconv.Itoa(h.age)+ " years)"
}

type HumanGroup []Human //HumanGroup is a type of slices that contain Humans

func (g HumanGroup) Len() int {
    return len(g)
}

func (g HumanGroup) Less(i, j int) bool {
    if g[i].age < g[j].age {
        return true
    }
    return false
}

func (g HumanGroup) Swap(i, j int){
    g[i], g[j] = g[j], g[i]
}

func main(){
    group := HumanGroup{
        Human{name:"Bart", age:24},
        Human{name:"Bob", age:23},
        Human{name:"Gertrude", age:104},
        Human{name:"Paul", age:44},
        Human{name:"Sam", age:34},
        Human{name:"Jack", age:54},
        Human{name:"Martha", age:74},
        Human{name:"Leo", age:4},
    }

    //Let's print this group as it is
    fmt.Println("The unsorted group is:")
    for _, v := range group{
        fmt.Println(v)
    }

    //Now let's sort it using the sort.Sort function
    sort.Sort(group)

    //Print the sorted group
    fmt.Println("\nThe sorted group is:")
    for _, v := range group{
        fmt.Println(v)
    }
}

輸出:

The unsorted group is:
(name: Bart - age: 24 years)
(name: Bob - age: 23 years)
(name: Gertrude - age: 104 years)
(name: Paul - age: 44 years)
(name: Sam - age: 34 years)
(name: Jack - age: 54 years)
(name: Martha - age: 74 years)
(name: Leo - age: 4 years)

The sorted group is:
(name: Leo - age: 4 years)
(name: Bob - age: 23 years)
(name: Bart - age: 24 years)
(name: Sam - age: 34 years)
(name: Paul - age: 44 years)
(name: Jack - age: 54 years)
(name: Martha - age: 74 years)
(name: Gertrude - age: 104 years)

搞定了,如我們所預(yù)料的那樣。

我們沒有實(shí)現(xiàn)HumanGroup的排序函數(shù),所做的只是實(shí)現(xiàn)了三個(gè)函數(shù)(Len,Less和Swap),這個(gè)就是sort.Sort函數(shù)需要的全部信息。

我知道你很奇怪,你很想知道這個(gè)神奇之處是怎么實(shí)現(xiàn)的。實(shí)際上他的實(shí)現(xiàn)很簡(jiǎn)單,Sort包的排序函數(shù)接受任意類型的參數(shù),只要他實(shí)現(xiàn)了Sort接口類型。

我們嘗試了幾種不同的利用接口類型作為參數(shù)的例子,這些例子利用接口類型達(dá)到了抽象數(shù)據(jù)類型的目的。

我們接下來(lái)嘗試一下,寫一個(gè)接受特定接口類型的函數(shù)來(lái)驗(yàn)證一下我們是否理解了Interface類型。

Our own example

我們過(guò)去使用過(guò)Max(s []int) int 和 Older(s []Person) Person函數(shù)。他們都實(shí)現(xiàn)了相似的功能。實(shí)際上,實(shí)現(xiàn)一個(gè)切片的最大值就在做一件事:迭代處理和比較。

讓我們嘗試一下:

package main
import (
    "fmt"
    "strconv"
)

//A basic Person struct
type Person struct {
    name string
    age int
}

//Some slices of ints, floats and Persons
type IntSlice []int
type Float32Slice []float32
type PersonSlice []Person

type MaxInterface interface {
    // Len is the number of elements in the collection.
    Len() int
    //Get returns the element with index i in the collection
    Get(i int) interface{}
    //Bigger returns whether the element at index i is bigger that the j one
    Bigger(i, j int) bool
}

//Len implementation for our three types
func (x IntSlice) Len() int {return len(x)}
func (x Float32Slice) Len() int {return len(x)}
func (x PersonSlice) Len() int {return len(x)}

//Get implementation for our three types
func(x IntSlice) Get(i int) interface{} {return x[i]}
func(x Float32Slice) Get(i int) interface{} {return x[i]}
func(x PersonSlice) Get(i int) interface{} {return x[i]}

//Bigger implementation for our three types
func (x IntSlice) Bigger(i, j int) bool {
    if x[i] > x[j] { //comparing two int
        return true
    }
    return false
}

func (x Float32Slice) Bigger(i, j int) bool {
    if x[i] > x[j] { //comparing two float32
        return true
    }
    return false
}

func (x PersonSlice) Bigger(i, j int) bool {
    if x[i].age > x[j].age { //comparing two Person ages
        return true
    }
    return false
}

//Person implements fmt.Stringer interface
func (p Person) String() string {
    return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
}

/*
 Returns a bool and a value
 - The bool is set to true if there is a MAX in the collection
 - The value is set to the MAX value or nil, if the bool is false
*/
func Max(data MaxInterface) (ok bool, max interface{}) {
    if data.Len() == 0{
        return false, nil //no elements in the collection, no Max value
    }
    if data.Len() == 1{ //Only one element, return it alongside with true
        return true, data.Get(1)
    }
    max = data.Get(0)//the first element is the max for now
    m := 0
    for i:=1; i<data.Len(); i++ {
        if data.Bigger(i, m){ //we found a bigger value in our slice
            max = data.Get(i)
            m = i
        }
    }
    return true, max
}

func main() {
    islice := IntSlice {1, 2, 44, 6, 44, 222}
    fslice := Float32Slice{1.99, 3.14, 24.8}
    group := PersonSlice{
        Person{name:"Bart", age:24},
        Person{name:"Bob", age:23},
        Person{name:"Gertrude", age:104},
        Person{name:"Paul", age:44},
        Person{name:"Sam", age:34},
        Person{name:"Jack", age:54},
        Person{name:"Martha", age:74},
        Person{name:"Leo", age:4},
    }

    //Use Max function with these different collections
    _, m := Max(islice)
    fmt.Println("The biggest integer in islice is :", m)
    _, m = Max(fslice)
    fmt.Println("The biggest float in fslice is :", m)
    _, m = Max(group)
    fmt.Println("The oldest person in the group is:", m)
}

輸出:

The biggest integer in islice is : 222
The biggest float in fslice is : 24.8
The oldest person in the group is: (name: Gertrude - age: 104 years)

MaxInterface接口包含三個(gè)方法簽名,滿足該接口的數(shù)據(jù)類型需要實(shí)現(xiàn)這三個(gè)方法。

  1. Len() int:必須返回集合數(shù)據(jù)結(jié)構(gòu)的長(zhǎng)度
  2. Get(int i) interface{}:必須返回一個(gè)在索引i的數(shù)據(jù)元素
  3. Bigger(i, j int) bool: 返回位于索引i和j的數(shù)值比較結(jié)果
    這個(gè)排序方式的實(shí)現(xiàn)是不是很簡(jiǎn)單直接。
    值得注意的是Max方法并沒有要求任何關(guān)于具體數(shù)據(jù)類型參數(shù)的信息。我們利用接口類型MaxInterface實(shí)現(xiàn)了數(shù)據(jù)抽象。

好了,就先到這里吧,再見!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,733評(píng)論 18 399
  • 面向?qū)ο笾饕槍?duì)面向過(guò)程。 面向過(guò)程的基本單元是函數(shù)。 什么是對(duì)象:EVERYTHING IS OBJECT(萬(wàn)物...
    sinpi閱讀 1,079評(píng)論 0 4
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,830評(píng)論 0 11
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態(tài)方法,可以作為本類的靜態(tài)方法來(lái)...
    XLsn0w閱讀 1,258評(píng)論 0 2
  • 風(fēng)似君,景似君, 風(fēng)景一窗慰我心。 斜陽(yáng)影里尋。 憶情真,思情真, 粉面難堪頰起皴。 可憐曲院人。 **** 不去...
    木昜_dl閱讀 357評(píng)論 14 24