er3456qi

er3456qi 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

是个好人

个人动态

er3456qi 回答了问题 · 2016-02-20

解决作为一位c#程序员。已基本入门。求推荐书籍进行提升

如果只是基本入门,《CLR via C#》先不要看。先看看《C# 本质论》,然后《深入理解C#》,然后《Framework Design Guidelines》,后面再考虑看看CLR相关的

关注 8 回答 7

er3456qi 发布了文章 · 2016-02-16

Try Redis : Redis 入门教程

开篇

Redis 是一种以键值对(key-value)存储数据的NoSQL数据库。

键值对存储数据的本质是以某个键存储某个值。之后你可以用这个键把存储的值取出来。可以用SET命令以键‘servername’存储值‘fido’:

SET servername 'fido'

这样,数据就被存储了,之后可以使用GET取出刚刚存储的数据:

GET servername // 返回 "fido"

对于数据的操作,还有一些基本的命令,比如INCRDEL

INCR 用于原子地递增一个数值数据。而DEL则是删除一个值。

SET connections 10
INCR connections // 返回 11
INCR connections // 返回 12
DEL connections
INCR connections // 返回 1

给值指定寿命

可以通过EXPIRE设置一个值的存活时间,过了这个时间,该值就会被删除。通过TTL可以查看值的存活时间。

对于TTL

  • 如果一个值没有设置存活时间,那么TTL会返回-1,表示这个值不会过期(这是值的默认寿命:长生);

  • 如果一个值设置了存活时间,在存活时间内,对值使用TTL会返回相应的生命剩余时间;

  • 如果对一个不存在的值或是已经超过存活时间(会被删除)的值使用TTL,会返回-2

注意,每使用SET设置一个值时,该值的TTL都会被重置为默认。

例子:

SET resource:lock 'Redis Demo 1'
TTL resource:lock // 返回 -1

EXPIRE resource:lock 120 //设置存活时间为120秒

// 7秒后
TTL resource:lock // 返回 113
// 120秒以后
TTL resource:lock // 返回 -2

SET resource:lock 'Redis Demo 2'
TTL resource:lock // 返回 -1
 

列表(list)

Redis也支持一些复杂的/复合的(complex)数据结构。这里第一个要说的是列表。列表是一系列有序的值的集合。
与列表交互的几个重要方法有:RPUSH, LPUSH, LLEN, LRANGE, LPOPRPOP

  • RPUSHLPUSH用于在列表的右端和左端插入数据。

  • LLEN返回列表的长度。

  • LRANGE返回一个子列表,它接收两个参数,它们标识你所要的子序列的首尾元素在原序列的位置。
    如果第二个元素是-1,则表示到序列的末尾。

  • LPOPRPOP删除并返回左右两端的第一个元素(跟栈的pop一样)。

例子(不用显式的创建列表,在向一个不存在的列表中插入值时,列表会被自动创建,当列表中的最后一个元素被pop后,列表会被自动删除):

RPUSH friends "Alice" // 创建一个列表friends并对其添加一个元素"Alice"
RPUSH friends "Bob"  // 向friends添加元素"Bob"
LPUSH friends "Sam" // 向friends添加元素"Sam"

LRANGE friends 0 -1 // 返回 1) "Sam", 2) "Alice", 3) "Bob"
LRANGE friends 0 1 // 返回 1) "Sam", 2) "Alice"
LRANGE friends 1 2 // 返回 1) "Alice", 2) "Bob"

LLEN friends // 返回 3
LPOP friends // 返回 "Sam"
RPOP friends // 返回 "Bob"

LLEN friends // 返回 1
LRANGE friends 0 -1 // 返回 1) "Alice"

集合(set)

集合跟列表类似,但是集合是无序的,且集合内元素唯一。

集合的几个常用命令为:SADD, SREM, SISMEMBER, SMEMBERSSUNION

  • SADD 向集合中添加值。

  • SREM 从集合中删除给定的值。

  • SISMEMBER 接收一个参数,用以判断该参数的值是否在集合中,若在集合中返回1,否则返回0。
    如果不给参数,则返回整个列表。

  • SMEMBERS 返回集合中所有元素。

  • SUNION 合并两个集合。

例子(跟列表一样,集合也不用显式创建):

SADD superpowers "flight"
SADD superpowers "x-ray vision"
SADD superpowers "reflexes"

SREM superpowers "reflexes"

SISMEMBER superpowers "flight" // 返回 1
SISMEMBER superpowers "reflexes" // 返回 0

SMEMBERS superpowers // 返回 1) "flight", 2) "x-ray vision"

SADD birdpowers "pecking"
SADD birdpowers "flight"
SUNION superpowers birdpowers // 返回 1) "pecking", 2) "x-ray vision", 3) "flight"

有序集合(Sorted Sets)

集合是个很好用的数据结构,但是因为它是无序的,在某些情况下使用会不太方便。所以Redis 1.2 引入了有序集合。

有序集合的命令是Z开头,比如:有序集合的数据插入用的是ZADD而不是SADD
有序集合跟常规集合类似,不过有序集合的每个值都有一个与其关联的分数(associated score),这个分数用于排序集合内元素。

来一个例子:

ZADD hackers 1940 "Alan Kay"
ZADD hackers 1906 "Grace Hopper"
ZADD hackers 1953 "Richard Stallman"
ZADD hackers 1965 "Yukihiro Matsumoto"
ZADD hackers 1916 "Claude Shannon"
ZADD hackers 1969 "Linus Torvalds"
ZADD hackers 1957 "Sophie Wilson"
ZADD hackers 1912 "Alan Turing"

在例子中,第一个参数(出生年)是排序的分数,下面获取索引值2到4的元素(从0开始):

ZRANGE hackers 2 4 // 返回 1) "Claude Shannon", 2) "Alan Kay", 3) "Richard Stallman"

Hashes

Hashes 是字符串字段和字符串值之间的映射。所以它是表示对象的最佳数据类型:

HSET user:1000 name "John Smith"
HSET user:1000 email "john.smith@example.com"
HSET user:1000 password "s3cret"

使用HGETALL获得存储的数据(返回所有的字段名和字段值):


HGETALL user:1000

也可以把对象的属性一次设置完:

HMSET user:1001 name "Mary Jones" password "hidden" email "mjones@example.com"

获取某个特定字段:

HGET user:1001 name // 返回 "Mary Jones"

数值类型在hash字段中也是很好用的,比如原子地步进一个数啥的都是可以的:

HSET user:1000 visits 10
HINCRBY user:1000 visits 1 // 返回 11
HINCRBY user:1000 visits 10 // 返回 21
HDEL user:1000 visits
HINCRBY user:1000 visits 1 // 返回 1

结束

本文翻译自 Try Redis

到此为止,try redis教程结束。更多内容,请看下面链接:

查看原文

赞 1 收藏 31 评论 2

er3456qi 回答了问题 · 2016-02-15

Java真数组

第一次听说真数组,不过听过为伪数组,就像是前面同学说的,JavaScript的数组就是典型的伪数组。不过非要说真数组的话,你看的那个百科里的解释应该也算对。

但是说到数组,还有一个多维数组,它在不同的语言里实现也不一样,比如在C++里面,多维数组在内存里是连续的,但是在java里,多维数组的每一维在内存里很可能不是连续的。所以这个了解了就好,没有必要细究。

关于健壮性,没啥感觉。。。

关注 5 回答 4

er3456qi 回答了问题 · 2016-02-15

解决关于java的==的疑问

给你一个不太详细回答(因为不想再捣鼓java了,所以就没细查资料):

首先,int == Integer,这个比较应该是Integer对象发生了自动拆箱,
其实实际是这样比较的:
int == integer.intValue()

也就是说,

System.out.println("a==b:"+(a == b));

System.out.println("a==b:"+(a == b.intValue()));

编译后的结果是一样的。

你可以找java的反编译工具(比如jad),看看上面两种方式的class文件。

另外,对象跟对象使用 == 比较,确实比较的是地址,所以一般对象之间要比较的话都用equals,但是值类型的比较,比较的是值,所以你的结果就是那样的。

不过,还有一个类似的例子你可以试试:

Integer d = 127;
Integer e = 127;
System.out.println(d == e);

Integer g = 128;
Integer h = 128;
System.out.println(g == h);

看看结果。

最后,C sharp 大法好,退java保平安。

关注 8 回答 7

er3456qi 回答了问题 · 2016-02-06

x经问题: Why choose Ruby or Python over PHP for web development?

喜欢python不喜欢ruby,学了挺长时间的python 3,后来学了一点框架,webpy,django,tornado都入门了,然后后来发现国内好多公司用的都是python 2.× ,但是我想写2.x的代码,所以后来决定学了nodejs。。。

关注 4 回答 7

er3456qi 回答了问题 · 2016-02-03

怎么把c#程序转成java?

最简单的方法是手动重写一遍

关注 12 回答 11

er3456qi 回答了问题 · 2016-02-03

python解析html,哪个库好用点?

BeautifulSoup

关注 8 回答 6

er3456qi 发布了文章 · 2016-02-03

Typescript Handbook 精简版之变量声明

变量声明

letconst 是JavaScript新出的两个变量声明的方式。前面说过letvar类似,但是它们的作用域是不一样的。

关于作用域,在ES6之前的Javascript中,函数体是唯一能能够创建新作用域的地方。那时候没有let,用var声明的变量,作用域要么是全局,要么是函数体,没有块级的作用域(块作用域变量在包含它们的块外部或for循环外部是不能被访问的)。而新版的Javascript引入了let关键字,用以声明一个块级域的本地变量,这样能避免一些问题。

至于const,它的作用域和let一样,但是是声明创建一个只读常量,这里要注意一下,这并不意味着该常量指向的值不可变,而是该常量只能被赋值一次!

举个例子:

// numLivesForCat的值不能再变了
const numLivesForCat = 9;
const kitty = {
    name: "Aurora",
    numLives: numLivesForCat,
}

// 错误,kitty指向的对象不能变
kitty = {
    name: "Danielle",
    numLives: numLivesForCat
};

// 没问题,对象的属性可以变化
kitty.name = "Rory";
kitty.name = "Kitty";
kitty.name = "Cat";
kitty.numLives--;

另外,使用const定义常量时,一定要初始化。

Typescript作为Javascript的超集,自然也是支持letconst的。

该用哪个

const没什么好说的,你需要常量就用它,不需要就不用。但是letvar要比较一下。

使用var声明变量时,不管你声明多少次,你得到的只有一个变量,而使用let时,同一个变量名在同一作用域内声明一次以上会报错。

使用var时很容易出bug,比如:

function sumMatrix(matrix: number[][]) {
    var sum = 0;
    for (var i = 0; i < matrix.length; i++) {
        var currentRow = matrix[i];
        for (var i = 0; i < currentRow.length; i++) {
            sum += currentRow[i];
        }
    }

    return sum;
}

里层for循环中的i会覆盖外层的i,因为i引用的都是相同的函数作用域内的变量。

但是如果把var换成let,内层的for循环自己是一个块级作用域,会屏蔽外部的作用域中的相同名字的变量,所以这两个i会井水不犯河水。

另外,因为var是函数作用域,所以对于一个var声明的变量,你可以先使用再声明:

bla = 2;
var bla;
// ...

// 可以理解为下面这样:

var bla;
bla = 2;

引用一段mozilla文档中的话:

由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这意味着变量可以在声明之前使用,这个行为叫做“hoisting”。

嗯,使用var时,这叫变量声明提升,但是如果你使用let时也这样做,这叫错误! 块级作用域的变量的一个特点是,它们不能在被声明之前使用

最后,建议尽量用let替换var

本文参考:

查看原文

赞 0 收藏 4 评论 0

er3456qi 发布了文章 · 2016-02-02

Typescript Handbook 精简版之基础类型

简介

Typescript支持与Javascript几乎一样的数据类型:布尔值、数字、字符串,结构体等,此外Typescript还提供了很实用的枚举类型。

Boolean(布尔值)

let isDone: boolean = false;

Number(数字)

和Javascript一样,Typescript中的数字都是浮点数。
Typescript中的数字支持二进制、八进制、十进制、十六进制。

let binary: number = 0b1010;
let octal: number = 0o744;
let decimal: number = 6;
let hex: number = 0xf00d;

String(字符串)

单双引号都可以,

let name: string = "bob";
name = 'smith';

支持跟C#一样的内嵌表达式,即使用反引号`包围内嵌字符串,然后以${}的方式嵌入变量:

let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.

I'll be ${ age + 1 } years old next month.`

Array(数组)

let list: number[] = [1, 2, 3];

或者这样定义:

let list: Array<number> = [1, 2, 3];

Tuple(元组)

跟python中的元祖一样,当然跟C#中的元组更像(因为有元素的类型声明):

// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error

Enum(枚举)

enum Color {Red, Green, Blue};
let c: Color = Color.Green;

枚举默认是从0开始为元素编号,也可以手动指定成员的数值:

enum Color {Red = 1, Green, Blue};
let c: Color = Color.Green;

或者全部指定元素编号:

enum Color {Red = 1, Green = 2, Blue = 4};
let c: Color = Color.Green;

可以通过枚举值获得枚举的名字:

enum Color {Red = 1, Green, Blue};
let colorName: string = Color[2];

alert(colorName); // Green

Any(任意类型)

通常为那些在编程阶段还不能够确认数据类型的变量指定为Any类型。这些值可以来自动态内容,比如用户输入或是第三方库。
这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译时的检查。
这时候可以使用 any 类型:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

你可能觉得 anyObject 的作用一样。但是,实际并不是这样。
你的确可以给 Object 类型赋任何类型的值,然后你却不能在它上面调用任意方法(即使那个对象真的有这些方法)! 但是Any类型可以!

let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)

let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.

当你只知道一部分数据的类型的时候, any 类型也很有用。比如你有一个数组,数组内包含不同类型(如果类型全都知道,可是用Tuple):

let list: any[] = [1, true, "free"];

list[1] = 100;

Void(空类型)

void 有点类似于 any 的反义词: 它表示没有任何类型。通常用在没有返回值的方法:

function warnUser(): void {
    alert("This is my warning message");
}

声明一个 void 类型的变量没啥用,因为你只能给它赋值 undefined 或是 null

let unusable: void = undefined;

关于let

let 是Javascript新添加的一个关键字,功能了var类似,但是它们的作用域不一样(详细自己查)。let更像是其他语言中定义变量的关键字,所以尽量用let来替代var

注:原内容来自github上的官方Handbook,这里我只是做了精简加翻译。

写这个的目的是作为学习Typescript的笔记,当然发出来也是为了分享给对Typescript感兴趣的同学。学Typescript,最好有编程语言基础,最好是学过Javascript或是C#。

另外:这里有人翻译的完整版。

查看原文

赞 1 收藏 2 评论 0

er3456qi 发布了文章 · 2015-07-28

回调函数,就是回头再调用的函数

又遇到了回调函数,这次打算写下来分享一下。

所谓回调函数,或者在面向对象语言里叫回调方法,简单点讲,就是回头在某个时间(事件发生)被调用的函数。

再详细点:就是一个函数A,作为参数,传入了另一个函数B,然后被B在某个时间调用。

这里可以有疑问了,既然是一个函数调用另一个函数,可以在函数体里面调用啊,为什么还要把函数作为参数传到另一个函数里被调用?何况还有一些语言(比如java)不支持把函数作为参数。

对的,确实可以在函数体里调用另一个函数,功能上好像是没差别的,但是这里有一个问题,就是你要调用的这个函数被写死了,也就是说这样函数B只能调用函数A了,这样如果在另一个情景下,有个与A不同实现的函数C也需要在B的某个时刻被调用,那怎么办。

下面继续说回调函数,在c/c++里,回调函数可以使用函数指针作为参数被另一个函数调用;在c#里,可以使用委托,如果是事件方法的话,还有event关键字;在python和javascript里,可以直接把函数当对象传参,这些语言都很好实现回调函数(方法),可是, java呢? 先说点题外话,自从学了C#,就不喜欢java了,曾经一度打算以后不再用java,可是现实并没有那么理想,我现在要做android,所以还是不能放下java,而且今天遇到这个回调函数的问题,也是从java里遇到的,我个人觉得,在这个博客里出现的语言,除了java外,对于回调,都可以既容易,又好理解的实现,但是java,我觉得并不是那样,不然我也不会来写这篇博客。

好了继续说,关于java中的回调方法的实现。这篇博客的重点就是说java的。 在java中,回调方法是用借用接口来实现的,我在网上找到一句话:

“把实现某一接口的类所创建的对象的引用,赋值给该接口声明的接口变量,那么该接口变量就可以调用被实现的接口的方法”。

很绕哈,简单解释下:
有一个接口,接口里有一个方法(这个方法就是要回调的方法):

interface CallBackInterface {
    void callBackMethod();
}

我们知道,接口对象不能直接用,因为里面的方法都没有实现。所以要找个类实现这个接口。
所以现在加一个类,实现这个接口:

interface CallBackInterface {
    void callBackMethod();
}

class CallBackClass implements CallBackInterface{

    @Override
    public void callBackMethod() {
        System.out.println("hello");
    }
}

好了,最后一步:把实现了接口的类的对象赋值给声明的接口变量(我给写进一个方法里了,然后外面加了个类的壳子):

public class CallBackTest {

    interface CallBackInterface {
        void callBackMethod();
    }

    class CallBackClass implements CallBackInterface {

        @Override
        public void callBackMethod() {
            System.out.println("hello");
        }
    }

    public void showCallBack() {
        CallBackInterface itfs = new CallBackClass();
        itfs.callBackMethod();
    }
}

现在可以调用试试看了:

public class Test {
    public static void main(String[] args) {
        new CallBackTest().showCallBack();
    }
}

没意外的话,会成功输出hello,反正我这边是的.

例子看完了,所以说我做了什么呢? 再详细点说,我们有一个要在某一个方法里被调用的方法(这个方法就是回调方法), 前面我们也说了,最好不要直接把想要回调方法做的事直接写在调用方法里, 又因为java里没法把方法当做参数传递,所以我们只好把这个回调方法放在了接口里(为什么不是类?不是抽象类?而是接口?你可以自己去找下抽象类与接口的异同,自己解决这个问题)。有接口的话,就要被类实现,然后,只要是给接口的对象赋予实现类的对象,这个接口的对象就可以调用那个方法了。理解这里的话,有一个重点,就是多态, 这里用到的多态知识就是,接口的对象可以顺利被子类赋值,并且调用子类的重写方法(类也有类似的概念)。

再多说一点,这里任何实现了CallbackInterface接口的类,都可以像下面这样放在new后面(就是赋值):

public class CallBackTest {
    interface CallBackInterface {
        void callBackMethod();
    }

    class CallBackClass implements CallBackInterface {

        @Override
        public void callBackMethod() {
            System.out.println("hello");
        }
    }

    class Controller {
        private CallBackInterface cbitf;
        // 这个boolean只是为了模拟有事件,没啥实用价值
        public boolean somethingHappend;
        // 这里确实可以直接把CallBackClass做参数,而且省掉接口的定义
        // 但是这样做的话,就像是回调函数直接写在了调用函数里一样
        // 不明白的话就好好理解下"约定"和"调用者不管回调函数是怎么实现的"吧
        public Controller(CallBackInterface itfs) {
            somethingHappend = true;
            this.cbitf = itfs;
        }

        public void doSomething() {
            if(somethingHappend) {
                cbitf.callBackMethod();
            }
        }
    }

    public void showCallBack() {
        CallBackClass cbc = new CallBackClass();
        Controller ctrlr = new Controller(cbc);
        ctrlr.doSomething();
        // 其实上面也可以这样写在一行里
        // new Controller(new CallBackClass()).doSomething();
    }
}

最后多说一点,其实这种应用在android里会经常遇到,我就是在学android的时候遇到的。

查看原文

赞 2 收藏 15 评论 0

认证与成就

  • 获得 18 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • ClearHTML

    一个过滤html中标签属性的工具

  • EasyLiteral

    一个ide/vscode的插件,用于便利的输入字符串数组和json键值对。

注册于 2015-04-22
个人主页被 309 人浏览