首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Docker技术笔记:Docker入门浅尝

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaobryant/article/details/79600059 简介 本文将用Docker的方式来构建一个应用APP。 过去,如果要开发一个Python应用APP,所需做的第一件事就是在开发机上安装Python运行时环境。在这种情形下,开发机的环境必须与APP所要求的环境一致,同时还需要与生产环境相匹配。 通过使用Docker,可以将一个可移植的Python运行时环境作为一个image获取,而无需安装。然后,就可以基于Python运行时环境image,将APP代码及其依赖库合并构建,从而简化了应用APP的部署难度。 用Dockerfile定义容器Container Dockerfile是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。它简化了业务部署的流程,大大提高了业务的部署速度。Dockerfile的产出为一个新的可以用于创建容器的镜像。 Dockerfile语法由两部分构成,分别是“注释”和“命令+参数”。 # Line blocks used for commenting COMMAND argument1 argument2 ... 对于Dockerfile,我们首先创建一个空目录,然后cd到该目录,并创建Dockerfile文件。 # Use an official Python runtime as a parent image FROM python:2.7-slim # Set the working directory to /app WORKDIR /app # Copy the current directory contents into the container at /app ADD . /app # Install any needed packages specified in requirements.txt RUN pip install --trusted-host pypi.python.org -r requirements.txt # Make port 80 available to the world outside this container EXPOSE 80 # Define environment variable ENV NAME World # Run app.py when the container launches CMD ["python", "app.py"] 其中,app.py和requirements.txt都位于与Dockerfile相同的目录下,具体如下: zjl@ubuntu:~/docker/pyapp$ ls app.py Dockerfile requirements.txt 对于requirements.txt,其内容如下: Flask Redis 对于app.py,其内容如下: from flask import Flask from redis import Redis, RedisError import os import socket redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) app = Flask(__name__) @app.route("/") def hello(): try: visits = redis.incr("counter") except RedisError: visits = "<i>cannot connect to Redis, counter disabled</i>" html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}<br/>" \ "<b>Visits:</b> {visits}" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits) if __name__ == "__main__": app.run(host="0.0.0.0", port=80) 现在,我们知道,pip install -r requirements.txt为Python安装了Flask和Redis库,同时APP会打印出环境变量NAME,同时将socket.gethostname()打印出来。 构建新的image镜像 下面,我们进行构建,具体如下: zjl@ubuntu:~/docker/pyapp$ ls app.py Dockerfile requirements.txt zjl@ubuntu:~/docker/pyapp$ sudo docker build -t fhello . Sending build context to Docker daemon 4.608kB Step 1/7 : FROM python:2.7-slim 2.7-slim: Pulling from library/python d2ca7eff5948: Pull complete cef69dd0e5b9: Pull complete 50e1d7e4f3c6: Pull complete 861e9de5333f: Pull complete Digest: sha256:e9baca9b405d3bbba71d4c3c4ce8a461e4937413b8b910cb1801dfac0a2423aa Status: Downloaded newer image for python:2.7-slim ---> 52ad41c7aea4 Step 2/7 : WORKDIR /app ... Step 3/7 : ADD . /app ... Step 4/7 : RUN pip install --trusted-host pypi.python.org -r requirements.txt ... Step 5/7 : EXPOSE 80 ... Step 6/7 : ENV NAME World ... Step 7/7 : CMD ["python", "app.py"] ... Successfully built d3fafd68e807 Successfully tagged fhello:latest zjl@ubuntu:~/docker/pyapp$ sudo docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE fhello latest 12d000cd7a1b 12 minutes ago 148MB 运行新的image镜像 $ sudo docker run -p 4000:80 fhello * Running on http://0.0.0.0:80/ (Press CTRL+C to quit) # 访问该网站 $ curl localhost:4000 <h3>Hello World!</h3><b>Hostname:</b> f4e37f061593<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i> $ sudo docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4a150bdc67cd fhello "python app.py" 10 seconds ago Up 9 seconds 0.0.0.0:4000->80/tcp upbeat_austin 关闭容器,命令如下: $ sudo docker container stop 4a150bdc67cd 4a150bdc67cd 给镜像打上标签 syntax: -->> docker tag image username/repository:tag $ sudo docker tag fhello zhjl/getstarted:alpha-1 $ sudo docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE fhello latest 12d000cd7a1b 18 minutes ago 148MB zhjl/getstarted alpha-1 12d000cd7a1b 18 minutes ago 148MB $ docker run -p 4000:80 zhjl/getstarted:alpha-1 Recap and cheat sheet # Create image using this directory's Dockerfile docker build -t fhello . # Run "friendlyname" mapping port 4000 to 80 docker run -p 4000:80 fhello # Same thing, but in detached mode docker run -d -p 4000:80 fhello # List all running containers docker container ls # List all containers, even those not running docker container ls -a # Gracefully stop the specified container docker container stop <hash> # Force shutdown of the specified container docker container kill <hash> # Remove specified container from this machine docker container rm <hash> # Remove all containers docker container rm $(docker container ls -a -q) # List all images on this machine docker image ls -a # Remove specified image from this machine docker image rm <image id> # Remove all images from this machine docker image rm $(docker image ls -a -q) # Log in this CLI session using your Docker credential docker login # Tag <image> for upload to registry docker tag <image> username/repository:tag # Upload tagged image to registry docker push username/repository:tag # Run image from a registry docker run username/repository:tag

优秀的个人博客,低调大师

Python入门(八)分支与循环

分支 先例 写一个程序,按百分制评等级:[90,100]等级为A,[80,90)等级为B,[60,80)等级为C,[0,60)等级为D,当用户输入分数时,自动转换为ABCD的形式输出。 rank1.py >>> score = int ( input ('Please Input the Score:')) if score < 0 or score > 100: print ('Input Error!') if 90 <= score <= 100: print ('A') if 80 < score <90: print ('B') if 60 < score <=80: print ('C') if 0 <= score <=60: print ('D') F5运行后,输入分数: rank2.py >>> score = int ( input ('Please Input the Score:')) if score < 0 or score > 100: print ('Input Error!') elif 90 <= score <= 100: print ('A') elif 80 < score <90: print ('B') elif 60 < score <=80: print ('C') elif 0 <= score <=60: print ('D') F5运行后,输入分数: rank3.py >>> score = int ( input ('Please Input the Score:')) if score < 0 or score > 100: print ('Input Error!') else: if 90 <= score <= 100: print ('A') else: if 80 < score <90: print ('B') else: if 60 < score <=80: print ('C') else: print ('D') F5运行后,输入分数: rank1 VS rank2 VS rank3 rank1的特点:不论程序执行到哪一步能满足条件,都会把整个程序都走一遍,再输出结果。 rank2的特点:只要程序执行到满足条件的那一步,就会终止程序输出结果,比rank1节省时间。 rank3的特点:与rank2的执行方式一样,只是运用了python中特有的elif语句,简洁明了!rank2体现了python中的缩进机制,完美的避开了,在其他语言中经常会掉的坑。 悬挂else 像C语言中有如下代码: if (a > 0) if (b > 0) printf("^_^") else printf("&-&"); 请问else是和哪个if搭配的呢?对和第二个if搭配!BUT,在大量代码面前,这种框架的关键字像沧海一粟,找起来很费劲。所以,悬挂else的问题在python中完全不存在。 条件表达式(三元操作符) 买家秀: x,y = 1,2 if x < y: print('min =',x) else: print('min =',y) F5运行后得: 卖家秀: x,y =1,2 print('min =', x if x < y else y) F5运行后得:即使得到相同的结果,过程仍可能有很大的差别!由上述对比可知,条件表达式的语法为: x if 条件 else y 当条件为真时,程序将返回x的值,反之,返回y的值。 断言(assert) >>> assert 1 > 2 Traceback (most recent call last): File "<pyshell#8>", line 1, in <module> assert 1 > 2 AssertionError 由此异常可知,关键字 assert 后的条件为假时程序便会产生AssertionError,所以说,当我们需要确保程序中的某一个条件一定为真才能让程序正常工作的话时,用assert在程序中置入检查点。 循环 while 循环 while 条件: 循环体 只要条件为真,程序就会一直执行循环体。 while 1: str1=str(input("你现在有什么想法:")) print("原来你很",str1,"呀!") for 循环 for 目标 in 表达式: 循环体 目标是指变量,表达式可为序列,可以是列表也可以是字符串。 >>> players = ['网易云音乐','酷狗音乐','QQ音乐'] >>> for player in players: print ('安装:',player,len(player)) 安装: 网易云音乐 5 安装: 酷狗音乐 4 安装: QQ音乐 4 for 与很多BIF连用时会实现各种各样的功能,这里以range([star,]stop[,step=1])为例: >>> for i in range(1,10,2): print(i) 1 3 5 7 break和continue 关键字break的作用是终止当前循环,跳出循环体。 >>> for i in '123456789': if i == '7': break print(i) 1 2 3 4 5 6 关键字continue的作用是终止当前循环,开始下次循环。 >>> for i in '123456789': if i == '7': continue print(i) 1 2 3 4 5 6 8 9 需要注意,循环语句可以有 else 子句,它在穷尽列表(以for循环)或条件变为 false (以while循环)导致循环终止时被执行,但循环被break终止时不执行。 >>> for i in range(1,10): for x in range(2,i): if i % x == 0: print(i,'能分解成',x,'*',i//x) break else: print(i,'是质数!') 1 是质数! 2 是质数! 3 是质数! 4 能分解成 2 * 2 5 是质数! 6 能分解成 2 * 3 7 是质数! 8 能分解成 2 * 4 9 能分解成 3 * 3 END!

优秀的个人博客,低调大师

Python入门(一)了解与安装

一、了解Python Python的定义 Python是一种面向对象的服务器端解释性、开源、非编译的脚本语言,可单独使用,也可作为框架组成部分使用。 Python的特点 1.适用领域 web开发:django、pyramid、tornado、bottle、flask、web.py。 网络编程:twisted、requests、scrapy、paramiko。 科学运算:scipy、pandas、ipython。 GUI图形开发:wxpython、pyqt、kivy。 运维自动化:openstack、saltstack、ansible、腾讯蓝鲸。 2.不适用领域 贴近硬件的代码(首选C)。 移动开发(iOS/Android都有各自的开发语言)。 Python的一些编程语言功能 有多种基本数据类型:数字(浮点型,复数型和无限长的长整型),字符串(包括ASCII和Unicode),列表和字典。 Python支持类和多继承。 代码可以加载到模块和包中。 支持错误捕捉。 混合不兼容的类型(例如试图添加一个字符串和一个数字)会引发异常,所以错误会很快被捕获。 Python包含高级编程功能,如生成程序和列表。 Python的自动内存管理,让你不必再手动分配和释放内存。 二、安装Python 1.点击链接进入Python官网2.在当前页面底部,点击Downloads下的windows(根据自己系统选择) 3. 系统是32bit的选x86,64bit选x86-64, 关于选python2.x还是python3.x,如果初学python我建议学python3.x,如果以前用过python2.x,建议你参考python2 or python3; web-based installer 是通过联网的方式进行安装; executable installer 是通过可执行文件(*.exe)的方式进行安装; embeddable zip file 是一个嵌入式压缩文件,可以集成到其它应用中。我选择的是Windows x86-64 executable installer。 4.下载后,将电脑运行中的杀毒软件退出,以管理员身份运行(*.exe)文件,开始安装Python。 注意最下面的 Add Python 3.7 to PATH,意思是,把python的安装路径添加到系统路径下面。如果勾选,不用再手动配置环境;如果不勾选,需要安装后手动设置路径,这里推荐勾选。5.点击Install Now(默认安装路径和安装文件),安装过程约1分钟。6.如果安装过程出现以下问题: 很可能是杀软没退出,退出后重试。7.界面显示Setup was successful 说明安装成功了,点close关闭即可。8.验证是否成功安装。 快捷键Win+R,调出运行窗口,输入cmd,然后确定; 再输入python,显示如下 说明安装成功。注意:如果在上述第4步中没有勾选Add Python 3.7 to PATH,这里会显示‘python ’不是内部或外部命令,也不是可运行的程序或批处理文件。 三、启动Python 1.双击IDLE启动python; 2.在 >>> 后键入语句 print("Hello,DJY!"),回车; 3.进行简单尝试: END!

优秀的个人博客,低调大师

Scala的安装,入门,学习,基础

1:Scala的官方网址:http://www.scala-lang.org/ 推荐学习教程:http://www.runoob.com/scala/scala-tutorial.html Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。 2:Scala的优点: (1):优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API是否优雅直接影响用户体验。 (2):速度快:Scala语言表达能力强,一行代码抵得上Java多行,开发速度快;Scala是静态编译的,所以和JRuby,Groovy比起来速度会快很多。 (3):能融合到Hadoop生态圈:Hadoop现在是大数据事实标准,Spark并不是要取代Hadoop,而是要完善Hadoop生态。JVM语言大部分可能会想到Java,但Java做出来的API太丑,或者想实现一个优雅的API太费劲。 看到下面的图,突然想笑: 3:Scala的安装(Scala编译器安装,) (1):安装JDK: 因为Scala是运行在JVM平台上的,所以安装Scala之前要安装JDK; (2):Windows安装Scala编译器: 访问Scala官网http://www.scala-lang.org/下载Scala编译器安装包,目前最新版本是2.12.x,但是目前大多数的框架都是用2.10.x编写开发的,所以这里推荐2.10.x版本,下载scala-2.10.6.msi后点击下一步就可以了; (3):Linux安装Scala编译器: 1 下载Scala地址http://downloads.typesafe.com/scala/2.10.6/scala-2.10.6.tgz然后解压Scala到指定目录 2 tar -zxvf scala-2.10.6.tgz -C /usr/java 3 配置环境变量,将scala加入到PATH中 4 vi /etc/profile 5 export JAVA_HOME=/usr/java/jdk1.7.0_45 6 export PATH=$PATH:$JAVA_HOME/bin:/usr/java/scala-2.10.6/bin 4:Scala开发工具安装(个人喜好,Eclipse): 目前Scala的开发工具主要有两种:Eclipse和IDEA,这两个开发工具都有相应的Scala插件,如果使用Eclipse,直接到Scala官网下载即可http://scala-ide.org/download/sdk.html。 由于IDEA的Scala插件更优秀,大多数Scala程序员都选择IDEA,可以到http://www.jetbrains.com/idea/download/下载社区免费版,点击下一步安装即可,安装时如果有网络可以选择在线安装Scala插件。这里我们使用离线安装Scala插件: 推荐IDEA安装:http://www.cnblogs.com/xinhudong/p/8044292.html (1):安装IDEA,点击下一步即可。由于我们离线安装插件,所以点击Skip All and Set Defaul (2):下载IEDA的scala插件,地址http://plugins.jetbrains.com/?idea_ce (3):安装Scala插件:Configure -> Plugins -> Install plugin from disk -> 选择Scala插件 -> OK -> 重启IDEA; 5:开始学习Scala基础知识和语法: 这里先安装一下吧,下篇再开始学习Scala语法和基础知识: 打开官网,点击Download进行下载: 然后选择自己想要的版本: 然后我选择我想要版本: 拉到最下面,可以选择解压缩版本和安装版本进行下载即可: scala-2.10.6.rpm是RedHat的,scala-2.10.6.deb是Debian的。 我这里两种window方式都下载了,使用解压缩的方式进行安装,方便,快捷: 解压缩操作就不说了吧,然后配置环境变量,如下所示: 右击我的电脑,单击"属性",进入如图所示页面。下面开始配置环境变量,右击【我的电脑】--【属性】--【高级系统设置】--【环境变量】,如图: 然后设置 Path 变量:找到系统变量下的"Path"如图,单击编辑。在"变量值"一栏的最前面添加如下的路径:%SCALA_HOME%\bin; 以上的为必须配置的,下面的我之前都配置了,这里贴一下。方便脑补。 设置 Classpath 变量:找到找到系统变量下的"Classpath"如图,单击编辑,如没有,则单击"新建": "变量名":CLASSPATH "变量值":.;%SCALA_HOME%\bin;%SCALA_HOME%\lib\dt.jar;%SCALA_HOME%\lib\tools.jar.; 注意:"变量值"最前面的 .; 不要漏掉。最后单击确定即可。 检查环境变量是否设置好了:调出"cmd"检查。单击 【开始】,在输入框中输入cmd,然后"回车",输入 scala,然后回车,如环境变量设置ok,你应该能看到这些信息。 scala -version查看版本; 直接输入scala进行操作scala; 这里对网上使用eclipse安装scala插件的博客进行测试了一下,还可以用的,脑补一下,希望可以帮助到你: 使用eclipse下载极慢,看网速,推荐替换,解压缩以后把plugins和features复制到eclipse目录,重启eclipse以后即可,这样操作较快。 https://www.cnblogs.com/xiyuan2016/p/6626825.html https://www.cnblogs.com/sunrise88/p/7130346.html 待续......

优秀的个人博客,低调大师

Docker-compose入门教程

前言 Docker-compose是一个定义和运行多个Docker应用的工具,你可以使用YMAL文件来配置你的服务,然后使用docker-compose命令,创建和启动所有你配置的的服务。compose可以在任何工作环境中使用,生产环境,开发环境,持续集成等等。 Docker 使用compose一般包括三个步骤: 使用Dockerfile定义App的环境,以便于可再次重复利用 在docker-compose.yml文件中定义服务,以便于多个Docker应用可以协作起来 最后,运行docker-compose up,然后compose回启动和运行整个App。 操作 确保你已经安装了Docker和Docker compose。 设置 创建目录 mkdir composetest cd composetest 创建app.py文件,python文件有严格的行缩进关系。如果缩进不一样会报错。 from flask import Flask from redis import Redis app = Flask(__name__) redis = Redis(host='redis', port=6379) @app.route('/') def hello(): count = redis.incr('hits') return 'Hello From Aihe! I have been seen {} times.\n'.format(count) if __name__ == "__main__": app.run(host="0.0.0.0", debug=True) 创建另外一个依赖文件requirements.txt,python的依赖关系。 flask redis 创建Dockerfile文件 内容如下 FROM python:3.4-alpine ADD . /code WORKDIR /code RUN pip install -r requirements.txt CMD ["python", "app.py"] 在compose文件定义服务 文件内容如下 version: '3' services: web: build: . ports: - "5000:5000" volumes: - .:/code redis: image: "redis:alpine" 这个文件包含两个服务,web与redis web服务 Build 使用Dockerfile来构建镜像 Ports 主机转发5000端口到容器对应的5000端口 Volumes 挂载当前目录到容器内的/code目录下,我们可以直接修改本地文件,然后容器内会立即生效 构建和运行app 在当前目录下运行docker-compose up 当前目录结构为 当前目录内容 docker-compose up 在浏览器中输入http://localhost:5000/ 测试结果 我们可以以修改app.py文件中return的内容,可以看到浏览器立即生效。 额外 在配置的过程中,可能compose文件配置有错误,到底第一次无法启动服务。这时候重新构建服务。 docker-compose build --no-cache 后台运行与停止compose服务 docker-compose up -d docker-compose stop 最后 Docker确实给我们提供了极大的便利,使用的过程发现有以下好处 本地环境无需更改,直接使用Docker容器做测试 搭建集群直接使用容器,一台机器也可以完成 这里简单的介绍了docker-compose的用法,希望能对大家有帮助。

优秀的个人博客,低调大师

swift:入门知识之简单值

1、swift中用let关键字类定义常量,用var关键字来定义变量。 2、swift语句的结尾不需要再带逗号,系统在运行程序时自动会帮你添加上 3、一个变量或常量必须与赋值时拥有相同的类型。 4、如果初始化值没有提供足够的信息(或没有初始化值),可以在变量名后写类型,并用冒号分隔。 5、如果第一次赋初值变量的类型不确定,它可以根据再一次赋值时来确定当前变量的数据类型。 命名规范: 常用数据类型: 类型别名: 新类型元组 : 字符和字符串: 具体举例如下: 用var定义隐式变量,开始赋初值不能确定类型,等第二次赋值后,类型即可确定,此时再赋值类型需要一样 //定义变量用var //不用加类型 //语句后面不用加分号 var str = "Hello, playground" println(str) //"Hello,palyground" var myVariable = 40 myVariable = 55 myVariable = 56.7 //myVariable = "hello world" //error,类型不匹配 用let定义常量,赋初值后,不允许再赋值 //定义常量用let let myConstant = 40 //myConstant = 55 //error,常量不可再赋值 显示的定义变量或常量的类型,变量或常量的后面跟上": 类型" //显示声明变量或常量的类型 var num:Int = 30 let num2:Double = 30.5 其他类型转化为字符串类型,采用String(...)的方式强制转换为字符串 //其他类型转换为字符串 let label = "The width is " let width = 94 let widthLabel = label + String(width) //"The width is 94" 字符串可以直接用"+"号连接成一个新的字符串 //字符串的连接直接用加号var str = "hello" var str2 = "good morning" println(str+" "+str2) //"hello good morning" 在字符串中用" \(...) "这种方式可以用来格式化字符串 //格式化字符串var num = 2.0 let str3 = "good morning \(num)" //"good mornig 2.0" 字符串其他运算: 定义数组,用[ ]括号,通过索引获取数组中的值 //定义数组,用[] var arr = [1,2,3,4] arr[1] = 6 println("\(arr)") //"6" 数组其他运算方式: 添加元素 数组元素个数和容量 遍历元素: 删除元素: 设置数组多个元素: 定义一个字典,也用[ ]括号,没有显示指定字典类型时,键和值类型要保持一致,通过键key获取对应的值。如果没有找到,就会将其新添加进字典中 //定义一个字典,也用[],键和值类型需要保持一致 var dic = ["name":"Tom","age":"20"] dic["age"] = "22" println("\(dic)") //["name":"Tom","age":"22"]dic["sex"]= "M"println("\(dic)") //["name":"Tom","age":"22","sex":"M"] 字典其他运算方式: 遍历字典: 删除元素: 定义未知类型的空数组或空字典 //创建空数组 var arr3 = [] //创建空字典 var dic3 = [:] 定义指定类型的空数组或空字典 //创建空的字符串数组 var emptyArray = [String]() emptyArray = ["Tom"]//创建空的泛型字典 var emptyDictionary = Dictionary<String,Float>() emptyDictionary = ["tom":20,"jobs":23] 创建元组,可以同时存放任意类型的数据 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 分类: Swift开发技术 本文转自当天真遇到现实博客园博客,原文链接: http://www.cnblogs.com/XYQ-208910/p/4902736.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

swift:入门知识之泛型

在尖括号里写一个名字来创建一个泛型函数或者类型 例如<T>、<Type> 可以创建泛型类、枚举和结构体 在类型后使用where来指定一个需求列表。例如,要限定实现一个协议的类型,需要限定两个类型要相同,或者限定一个类必须有一个特定的父类 先给一个具体举例如下: //泛型函数 func repeat<ItemType>(item:ItemType,times:Int)->[ItemType]{ var results:[ItemType] = [ItemType]() for i in 0..<times{ results.append(item) } return results } //第一个参数可以接收任意类型的数据 repeat("Tom", 4) //字符串 repeat(10, 5) //整数 repeat((1,2,3,4), 3) //元组 显示结果: swift泛型具体介绍: http://www.cocoachina.com/newbie/basic/2014/0612/8790.html 泛型代码可以让你写出根据自我需求定义、适用于任何类型的,灵活且可重用的函数和类型。它可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图。 泛型是 Swift 强大特征中的其中一个,许多 Swift 标准库是通过泛型代码构建出来的。事实上,泛型的使用贯穿了整本语言手册,只是你没有发现而已。例如,Swift 的数组和字典类型都是泛型集。你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。同样的,你也可以创建存储任何指定类型的字典(dictionary),而且这些类型可以是没有限制的。 泛型所解决的问题 这里是一个标准的,非泛型函数swapTwoInts,用来交换两个Int值: funcswapTwoInts(inouta:Int,inoutb:Int) lettemporaryA=a a=b b=temporaryA } 这个函数使用写入读出(in-out)参数来交换a和b的值,请参考写入读出参数。 swapTwoInts函数可以交换b的原始值到a,也可以交换a的原始值到b,你可以调用这个函数交换两个Int变量值: varsomeInt=3 varanotherInt=107 swapTwoInts(&someInt,&anotherInt) println("someIntisnow\(someInt),andanotherIntisnow\(anotherInt)") //输出"someIntisnow107,andanotherIntisnow3" swapTwoInts函数是非常有用的,但是它只能交换Int值,如果你想要交换两个String或者Double,就不得不写更多的函数,如 swapTwoStrings和swapTwoDoublesfunctions,如同如下所示: funcswapTwoStrings(inouta:String,inoutb:String){ lettemporaryA=a a=b b=temporaryA } funcswapTwoDoubles(inouta:Double,inoutb:Double){ lettemporaryA=a a=b b=temporaryA } 你可能注意到 swapTwoInts、 swapTwoStrings和swapTwoDoubles函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是Int、String和Double。 但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题。(一个这种泛型函数后面已经定义好了。) 注意: 在所有三个函数中,a和b的类型是一样的。如果a和b不是相同的类型,那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个String类型的变量和一个Double类型的变量互相交换值。如果一定要做,Swift 将报编译错误。 泛型函数 泛型函数可以工作于任何类型,这里是一个上面swapTwoInts函数的泛型版本,用于交换两个值: funcswapTwoValues<T>(inouta:T,inoutb:T){ lettemporaryA=a a=b b=temporaryA } swapTwoValues函数主体和swapTwoInts函数是一样的,它只在第一行稍微有那么一点点不同于swapTwoInts,如下所示: funcswapTwoInts(inouta:Int,inoutb:Int) funcswapTwoValues<T>(inouta:T,inoutb:T) 这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名(如In、String或Doubl)。占位类型名没有提示T必须是什么类型,但是它提示了a和b必须是同一类型T,而不管T表示什么类型。只有swapTwoValues函数在每次调用时所传入的实际类型才能决定T所代表的类型。 另外一个不同之处在于这个泛型函数名后面跟着的展位类型名字(T)是用尖括号括起来的()。这个尖括号告诉 Swift 那个T是swapTwoValues函数所定义的一个类型。因为T是一个占位命名类型,Swift 不会去查找命名为T的实际类型。 swapTwoValues函数除了要求传入的两个任何类型值是同一类型外,也可以作为swapTwoInts函数被调用。每次swapTwoValues被调用,T所代表的类型值都会传给函数。 在下面的两个例子中,T分别代表Int和String: varsomeInt=3 varanotherInt=107 swapTwoValues(&someInt,&anotherInt) //someIntisnow107,andanotherIntisnow3 varsomeString="hello" varanotherString="world" swapTwoValues(&someString,&anotherString) //someStringisnow"world",andanotherStringisnow"hello" 注意:上面定义的函数swapTwoValues是受swap函数启发而实现的。swap函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似swapTwoValues函数的功能,你可以使用已存在的交换函数swap函数。 类型参数 在上面的swapTwoValues例子中,占位类型T是一种类型参数的示例。类型参数指定并命名为一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来(如)。 一旦一个类型参数被指定,那么其可以被使用来定义一个函数的参数类型(如swapTwoValues函数中的参数a和b),或作为一个函数返回类型,或用作函数主体中的注释类型。在这种情况下,被类型参数所代表的占位类型不管函数任何时候被调用,都会被实际类型所替换(在上面swapTwoValues例子中,当函数第一次被调用时,T被Int替换,第二次调用时,被String替换。)。 你可支持多个类型参数,命名在尖括号中,用逗号分开。 命名类型参数 在简单的情况下,泛型函数或泛型类型需要指定一个占位类型(如上面的swapTwoValues泛型函数,或一个存储单一类型的泛型集,如数组),通常用一单个字母T来命名类型参数。不过,你可以使用任何有效的标识符来作为类型参数名。 如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swift 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两个类型参数为KeyType和ValueType,用来记住它们在你的泛型代码中的作用。 注意:请始终使用大写字母开头的驼峰式命名法(例如T和KeyType)来给类型参数命名,以表明它们是类型的占位符,而非类型值。 泛型类型 通常在泛型函数中,Swift 允许你定义你自己的泛型类型。这些自定义类、结构体和枚举作用于任何类型,如同Array和Dictionary的用法。 这部分向你展示如何写一个泛型集类型--Stack(栈)。一个栈是一系列值域的集合,和Array(数组)类似,但其是一个比 Swift 的Array类型更多限制的集合。一个数组可以允许其里面任何位置的插入/删除操作,而栈,只允许在集合的末端添加新的项(如同push一个新值进栈)。同样的一个栈也只能从末端移除项(如同pop一个值出栈)。 注意:栈的概念已被UINavigationController类使用来模拟试图控制器的导航结构。你通过调用UINavigationController的pushViewController:animated:方法来为导航栈添加(add)新的试图控制器;而通过popViewControllerAnimated:的方法来从导航栈中移除(pop)某个试图控制器。每当你需要一个严格的后进先出方式来管理集合,堆栈都是最实用的模型。 下图展示了一个栈的压栈(push)/出栈(pop)的行为: 1、现在有三个值在栈中; 2、第四个值“pushed”到栈的顶部; 3、现在有四个值在栈中,最近的那个在顶部; 4、栈中最顶部的那个项被移除,或称之为“popped”; 5、移除掉一个值后,现在栈又重新只有三个值。 这里展示了如何写一个非泛型版本的栈,Int值型的栈: structIntStack{ varitems= [Int]() mutatingfuncpush(item:Int){ items.append(item) } mutatingfuncpop()->Int{ returnitems.removeLast() } } 这个结构体在栈中使用一个Array性质的items存储值。Stack提供两个方法:push和pop,从栈中压进一个值和移除一个值。这些方法标记为可变的,因为他们需要修改(或转换)结构体的items数组。 上面所展现的IntStack类型只能用于Int值,不过,其对于定义一个泛型Stack类(可以处理任何类型值的栈)是非常有用的。 这里是一个相同代码的泛型版本: structStack<T>{ varitems= [T]() mutatingfuncpush(item:T){ items.append(item) } mutatingfuncpop()->T{ returnitems.removeLast() } } 注意到Stack的泛型版本基本上和非泛型版本相同,但是泛型版本的占位类型参数为T代替了实际Int类型。这种类型参数包含在一对尖括号里(<T>),紧随在结构体名字后面。 T定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示为“T”。在这种情况下,T在如下三个地方被用作节点: - 创建一个名为items的属性,使用空的T类型值数组对其进行初始化; - 指定一个包含一个参数名为item的push方法,该参数必须是T类型; - 指定一个pop方法的返回值,该返回值将是一个T类型值。 当创建一个新单例并初始化时, 通过用一对紧随在类型名后的尖括号里写出实际指定栈用到类型,创建一个Stack实例,同创建Array和Dictionary一样: varstackOfStrings=Stack<String>() stackOfStrings.push("uno") stackOfStrings.push("dos") stackOfStrings.push("tres") stackOfStrings.push("cuatro") //现在栈已经有4个string了 下图将展示stackOfStrings如何push这四个值进栈的过程: 从栈中pop并移除值"cuatro": letfromTheTop=stackOfStrings.pop() //fromTheTopisequalto"cuatro",andthestacknowcontains3strings 下图展示了如何从栈中pop一个值的过程: 由于Stack是泛型类型,所以在 Swift 中其可以用来创建任何有效类型的栈,这种方式如同Array和Dictionary。 类型约束 swapTwoValues函数和Stack类型可以作用于任何类型,不过,有的时候对使用在泛型函数和泛型类型上的类型强制约束为某种特定类型是非常有用的。类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。 例如,Swift 的Dictionary类型对作用于其键的类型做了些限制。在字典的描述中,字典的键类型必须是可哈希,也就是说,必须有一种方法可以使其是唯一的表示。Dictionary之所以需要其键是可哈希是为了以便于其检查其是否包含某个特定键的值。如无此需求,Dictionary即不会告诉是否插入或者替换了某个特定键的值,也不能查找到已经存储在字典里面的给定键值。 这个需求强制加上一个类型约束作用于Dictionary的键上,当然其键类型必须遵循Hashable协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如String,Int, Double和 Bool)默认都是可哈希。 当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如可哈希具有的类型特征是根据他们概念特征来界定的,而不是他们的直接类型特征。 类型约束语法 你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同): funcsomeFunction<T:SomeClass,U:SomeProtocol>(someT:T,someU:U){ //functionbodygoeshere } 上面这个假定函数有两个类型参数。第一个类型参数T,有一个需要T必须是SomeClass子类的类型约束;第二个类型参数U,有一个需要U必须遵循SomeProtocol协议的类型约束。 类型约束行为 这里有个名为findStringIndex的非泛型函数,该函数功能是去查找包含一给定String值的数组。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引值(Int),反之则返回nil: funcfindStringIndex(array: [String],valueToFind:String)->Int?{ for(index,value)inenumerate(array){ ifvalue==valueToFind{ returnindex } } returnnil } findStringIndex函数可以作用于查找一字符串数组中的某个字符串: letstrings=["cat","dog","llama","parakeet","terrapin"] ifletfoundIndex=findStringIndex(strings,"llama"){ println("Theindexofllamais\(foundIndex)") } //输出"Theindexofllamais2" 如果只是针对字符串而言查找在数组中的某个值的索引,用处不是很大,不过,你可以写出相同功能的泛型函数findIndex,用某个类型T值替换掉提到的字符串。 这里展示如何写一个你或许期望的findStringIndex的泛型版本findIndex。请注意这个函数仍然返回Int,是不是有点迷惑呢,而不是泛型类型?那是因为函数返回的是一个可选的索引数,而不是从数组中得到的一个可选值。需要提醒的是,这个函数不会编译,原因在例子后面会说明: funcfindIndex<T>(array: [T],valueToFind:T)->Int?{ for(index,value)inenumerate(array){ ifvalue==valueToFind{ returnindex } } returnnil } 上面所写的函数不会编译。这个问题的位置在等式的检查上,“if value == valueToFind”。不是所有的 Swift 中的类型都可以用等式符(==)进行比较。例如,如果你创建一个你自己的类或结构体来表示一个复杂的数据模型,那么 Swift 没法猜到对于这个类或结构体而言“等于”的意思。正因如此,这部分代码不能可能保证工作于每个可能的类型T,当你试图编译这部分代码时估计会出现相应的错误。 不过,所有的这些并不会让我们无从下手。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持Equatable协议。 任何Equatable类型都可以安全的使用在findIndex函数中,因为其保证支持等式操作。为了说明这个事实,当你定义一个函数时,你可以写一个Equatable类型约束作为类型参数定义的一部分: funcfindIndex<T:Equatable>(array: [T],valueToFind:T)->Int?{ for(index,value)inenumerate(array){ ifvalue==valueToFind{ returnindex } } returnnil } findIndex中这个单个类型参数写做:T: Equatable,也就意味着“任何T类型都遵循Equatable协议”。 findIndex函数现在则可以成功的编译过,并且作用于任何遵循Equatable的类型,如Double或String: letdoubleIndex=findIndex([3.14159,0.1,0.25],9.3) //doubleIndexisanoptionalIntwithnovalue,because9.3isnotinthearray letstringIndex=findIndex(["Mike","Malcolm","Andrea"],"Andrea") //stringIndexisanoptionalIntcontainingavalueof2 关联类型 当定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为typealias关键字。 关联类型行为 这里是一个Container协议的例子,定义了一个ItemType关联类型: protocolContainer{ typealiasItemType mutatingfuncappend(item:ItemType) varcount:Int{get} subscript(i:Int)->ItemType{get} } Container协议定义了三个任何容器必须支持的兼容要求: 必须可能通过append方法添加一个新item到容器里; 必须可能通过使用count属性获取容器里items的数量,并返回一个Int值; 必须可能通过容器的Int索引值下标可以检索到每一个item。 这个协议没有指定容器里item是如何存储的或何种类型是允许的。这个协议只指定三个任何遵循Container类型所必须支持的功能点。一个遵循的类型也可以提供其他额外的功能,只要满足这三个条件。 任何遵循Container协议的类型必须指定存储在其里面的值类型,必须保证只有正确类型的items可以加进容器里,必须明确可以通过其下标返回item类型。 为了定义这三个条件,Container协议需要一个方法指定容器里的元素将会保留,而不需要知道特定容器的类型。Container协议需要指定任何通过append方法添加到容器里的值和容器里元素是相同类型,并且通过容器下标返回的容器元素类型的值的类型是相同类型。 为了达到此目的,Container协议声明了一个ItemType的关联类型,写作typealias ItemType。The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide(这个协议不会定义ItemType是遵循类型所提供的何种信息的别名)。尽管如此,ItemType别名支持一种方法识别在一个容器里的items类型,以及定义一种使用在append方法和下标中的类型,以便保证任何期望的Container的行为是强制性的。 这里是一个早前IntStack类型的非泛型版本,适用于遵循Container协议: structIntStack:Container{ //originalIntStackimplementation varitems= [Int]() mutatingfuncpush(item:Int){ items.append(item) } mutatingfuncpop()->Int{ returnitems.removeLast() } //conformancetotheContainerprotocol typealiasItemType=Int mutatingfuncappend(item:Int){ self.push(item) } varcount:Int{ returnitems.count } subscript(i:Int)->Int{ returnitems[i] } } IntStack类型实现了Container协议的所有三个要求,在IntStack类型的每个包含部分的功能都满足这些要求。 此外,IntStack指定了Container的实现,适用的ItemType被用作Int类型。对于这个Container协议实现而言,定义 typealias ItemType = Int,将抽象的ItemType类型转换为具体的Int类型。 感谢Swift类型参考,你不用在IntStack定义部分声明一个具体的Int的ItemType。由于IntStack遵循Container协议的所有要求,只要通过简单的查找append方法的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。确实,如果上面的代码中你删除了 typealias ItemType = Int这一行,一切仍旧可以工作,因为它清楚的知道ItemType使用的是何种类型。 你也可以生成遵循Container协议的泛型Stack类型: structStack<T>:Container{ //originalStack<T>implementation varitems= [T]() mutatingfuncpush(item:T){ items.append(item) } mutatingfuncpop()->T{ returnitems.removeLast() } //conformancetotheContainerprotocol mutatingfuncappend(item:T){ self.push(item) } varcount:Int{ returnitems.count } subscript(i:Int)->T{ returnitems[i] } } 这个时候,占位类型参数T被用作append方法的item参数和下标的返回类型。Swift 因此可以推断出被用作这个特定容器的ItemType的T的合适类型。 扩展一个存在的类型为一指定关联类型 在使用扩展来添加协议兼容性中有描述扩展一个存在的类型添加遵循一个协议。这个类型包含一个关联类型的协议。 Swift的Array已经提供append方法,一个count属性和通过下标来查找一个自己的元素。这三个功能都达到Container协议的要求。也就意味着你可以扩展Array去遵循Container协议,只要通过简单声明Array适用于该协议而已。如何实践这样一个空扩展,在使用扩展来声明协议的采纳中有描述这样一个实现一个空扩展的行为: extensionArray:Container{} 如同上面的泛型Stack类型一样,Array的append方法和下标保证Swift可以推断出ItemType所使用的适用的类型。定义了这个扩展后,你可以将任何Array当作Container来使用。 Where 语句 类型约束中描述的类型约束确保你定义关于类型参数的需求和一泛型函数或类型有关联。 对于关联类型的定义需求也是非常有用的。你可以通过这样去定义where语句作为一个类型参数队列的一部分。一个where语句使你能够要求一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。你可写一个where语句,通过紧随放置where关键字在类型参数队列后面,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 下面的列子定义了一个名为allItemsMatch的泛型函数,用来检查是否两个Container单例包含具有相同顺序的相同元素。如果匹配到所有的元素,那么返回一个为true的Boolean值,反之,则相反。 这两个容器可以被检查出是否是相同类型的容器(虽然它们可以是),但他们确实拥有相同类型的元素。这个需求通过一个类型约束和where语句结合来表示: funcallItemsMatch< C1:Container,C2:Container whereC1.ItemType==C2.ItemType,C1.ItemType:Equatable> (someContainer:C1,anotherContainer:C2)->Bool{ //checkthatbothcontainerscontainthesamenumberofitems ifsomeContainer.count!=anotherContainer.count{ returnfalse } //checkeachpairofitemstoseeiftheyareequivalent foriin0..someContainer.count{ ifsomeContainer[i]!=anotherContainer[i]{ returnfalse } } //allitemsmatch,soreturntrue returntrue } 这个函数用了两个参数:someContainer和anotherContainer。someContainer参数是类型C1,anotherContainer参数是类型C2。C1和C2是容器的两个占位类型参数,决定了这个函数何时被调用。 这个函数的类型参数列紧随在两个类型参数需求的后面: C1必须遵循Container协议 (写作 C1: Container)。 C2必须遵循Container协议 (写作 C2: Container)。 C1的ItemType同样是C2的ItemType(写作 C1.ItemType == C2.ItemType)。 C1的ItemType必须遵循Equatable协议 (写作 C1.ItemType: Equatable)。 第三个和第四个要求被定义为一个where语句的一部分,写在关键字where后面,作为函数类型参数链的一部分。 这些要求意思是: someContainer是一个C1类型的容器。 anotherContainer是一个C2类型的容器。 someContainer和anotherContainer包含相同的元素类型。 someContainer中的元素可以通过不等于操作(!=)来检查它们是否彼此不同。 第三个和第四个要求结合起来的意思是anotherContainer中的元素也可以通过 != 操作来检查,因为他们在someContainer中元素确实是相同的类型。 这些要求能够使allItemsMatch函数比较两个容器,即便他们是不同的容器类型。 allItemsMatch首先检查两个容器是否拥有同样数目的items,如果他们的元素数目不同,没有办法进行匹配,函数就会false。 检查完之后,函数通过for-in循环和半闭区间操作(..)来迭代someContainer中的所有元素。对于每个元素,函数检查是否someContainer中的元素不等于对应的anotherContainer中的元素,如果这两个元素不等,则这两个容器不匹配,返回false。 如果循环体结束后未发现没有任何的不匹配,那表明两个容器匹配,函数返回true。 这里演示了allItemsMatch函数运算的过程: varstackOfStrings=Stack<String>() stackOfStrings.push("uno") stackOfStrings.push("dos") stackOfStrings.push("tres") vararrayOfStrings=["uno","dos","tres"] ifallItemsMatch(stackOfStrings,arrayOfStrings){ println("Allitemsmatch.") }else{ println("Notallitemsmatch.") } //输出"Allitemsmatch." 上面的例子创建一个Stack单例来存储String,然后压了三个字符串进栈。这个例子也创建了一个Array单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组否是不同的类型,但他们都遵循Container协议,而且他们都包含同样的类型值。你因此可以调用allItemsMatch函数,用这两个容器作为它的参数。在上面的例子中,allItemsMatch函数正确的显示了所有的这两个容器的items匹配。 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 分类: Swift开发技术 本文转自当天真遇到现实博客园博客,原文链接: http://www.cnblogs.com/XYQ-208910/p/4905273.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

swift:入门知识之类和对象

1、swift中使用class创建一个类。一个类的声明则是在类里作为常量或变量声明的,除了是在类的上下文中。在方法和函数中也是这么写的。 2、swift中使用init(...)作为初始化构造函数 3、swift中使用构造函数初始化成员变量时,格式为 : self.name = name.构造器的声明跟函数一样,除了会创建类的实例。每一个属性都需要赋值,无论在声明里还是在构造器里。 4、swift中使用deinit来创建一个析构函数,由系统自动调用来撤销对象,进行内存的清理工作 5、swift中子类继承父类时,一冒号:隔开。在继承标准根类时无需声明,所以你可以忽略超类 6、swift中子类重写父类的方法时,必须使用关键词override重载超类中的实现,如果没有这个关键词,编译器会报错 7、swift中可以设置get和set方法,例如如下所示: var perimeter: Double { //getter方法 get{ return slideLength } //setter方法 set{ slideLength = newValue/2 } } 具体举例如下: 定义一个没有构造函数的类Shape //声明一个没有构造函数的类 class Shape{ //成员变量,边数 var numberOfSides = 0 //成员方法 func simpleDescripton()->String{ return "A shape with \(numberOfSides) sides." } } //创建对象 var shape = Shape() //{numberOfSides 0} //设置成员变量 shape.numberOfSides = 4 //调用成员方法 shape.simpleDescripton() //"A shape with 4 sides" 定义一个子类NameShape继承上面的父类Shape,子类带一个init构造函数和一个deinit析构函数 //声明带构造函数的类,继承父类Shape class NameShape : Shape{ //形状的名字 var name:String //初始化方法 init(name:String){ self.name = name } //虚构方法,不可以显示调用,系统会在程序执行结束后自动调用,清理内存 deinit{ println("deinit") } //成员方法,重写父类的方法必须要加上关键字 override override func simpleDescripton()->String{ return "A shape with name:\(name) have \(numberOfSides) sides." } } //创建对象,参数名不可以省略 var nameshape:NameShape = NameShape(name:"rect") //{{numberOfSides 0} name"rect"} //设置成员变量 nameshape.numberOfSides = 4 //{{numberOfSides 4} name "rect"} //调用成员方法 nameshape.simpleDescripton() //"A shape with name:rect have 4 sides" 定义一个正方形类Square继承上面的父类NameShape,其实它也继承了根父类Shape,Square继承它父类所有公有的属性和方法,在初始化时,子类可以借助父类的初始化方法给它们共有的属性赋初值 //继承父类NameShape class Square: NameShape { //边长 var slideLength:Double = 0.0 //子类自己的初始化方法 init(slideLength:Double,name:String) { self.slideLength = slideLength //调用父类的初始化方法 super.init(name: name) //直接用从父类继承的边数属性 numberOfSides = 4 } //设置对象的set和get方法 var perimeter: Double { //getter方法 get{ return slideLength } //setter方法 set{ slideLength = newValue/2 } } //定义求面积的方法 func area() -> Double{ return slideLength*slideLength } override func simpleDescripton() -> String { return "A shape with name:\(name) have \(numberOfSides) sides.its area is \(area())" } } //创建对象时的参数名不可以省略 var square:Square = Square(slideLength:2,name:"正方形") square.perimeter = 6 square.simpleDescripton() //"A shape with name:正方形 have 4 sides .its area is 9.0" square.slideLength //3 可以给参数的参数名再设置一个名字,函数内部使用参数的原始名,调用时使用设置参数名的名称,即外部名,前一章函数部分已经介绍过 class Counter{ var count:Int = 0 //给第二个参数times再设置一个名称numberOfTimes,不过函数内部使用的还是times func incrementBy(amount: Int, numberOfTimes times: Int){ count += amount * times } } var counter = Counter() //创建一个对象//调用函数时,用的第二个参数的名称为numberOfTimes counter.incrementBy(2, numberOfTimes: 7) //14 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 分类: Swift开发技术 本文转自当天真遇到现实博客园博客,原文链接: http://www.cnblogs.com/XYQ-208910/p/4903057.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

saltstack安装部署与入门使用

一、saltstack简介 SaltStack 一种基于 C/S 架构的服务器基础架构集中化管理平台,管理端称为 Master,客户端称为 Minion。SaltStack 具备配置管理、远程执行、监控等功能,一般可以理解为是简化版的 Puppet 和加强版的 Func。SaltStack 本身是基于 Python 语言开发实现,结合了轻量级的消息队列软件 ZeroMQ 与 Python 第三方模块(Pyzmq、PyCrypto、Pyjinjia2、python-msgpack 和 PyYAML 等)构建. 本文不以最新版安装部署,以CentOS6.8_x64 python2.6.6 环境中 在epel源中稳定的版本进行yum安装 。如需要安装最新版本下载地址(readhat/CentOS系)https://repo.saltstack.com/index.html#rhel, 采用两台安装搭建基本的环境。一台做master/minion 一台minion 两台防火墙要么关闭 要么加上允许本地网段白名单类似 :-A INPUT -s 172.16.3.0/24 -j ACCEPT 关闭selinux. 二、安装 1,安装epel扩展源 #yum install epel-release -y 2、安装saltstack master # yum install salt-master sat-minion -y 修改主配置文件/etc/salt/master内容如下: 1 2 3 4 5 6 7 8 9 10 #catmaster|egrep-v'(^$|^#)' interface:0.0.0.0 #侦听地址 file_roots: #文件根目录 base: - /srv/salt #catminion|egrep-v'(^$|^#)' default_include:minion.d/*.conf master:127.0.0.1 #和master在同一台 id :minion_local #标识 #service salt-master start #service salt-minion start 2、安装minion(非master上) #yum install epel-release -y #yum install salt-minion -y 修改配置文件cat /etc/salt/minion 1 2 3 4 #catminion|egrep-v'(^$|^#)' default_include:minion.d/*.conf master:172.16.3.147 #和master在同一台 id :minion_local #标识 #service salt-minion start 三、master上添加minion 如里在master配置文件中打开 auto_accept: True 则所有的minon 将会自动被认证加入。自行考量。本次是手工添加 #salt-key -L 如图:Unaccepted Keys:中出现两个等待授权认证的minon #salt-key -A 输入y 接受所有minion认证 再次salt-key -L 查看已授权的minion会就看到 #salt "*" test.ping #查看所有的活动在线的minion 如图: 到此基本的saltstack master /minion 环境部署完成 四、saltstack常用操作 除了上面的添加minon和测试minion在线情况外,还有一些其他的模拟提供一些常用操作; 1、salt语法 salt [客户端id,即目标,支持正规表达式] [模块名,如state,cmd。其实都是salt的模块] [动作] 如: salt "*" test.ping 这里的"*"就是匹配的目标,表示 所有minion test是模块 ping是动作 目标有以下常用的五种形式: 指定目标主要有五种方式 a)、Global,即salt默认的匹配方式,能识别终端常用的通配符,如*代表所有 如,salt '*' test.ping b)、List,列表,需-L指定。 如,salt -L 'minion_local,minion_152' test.ping 其中minion_local,minion_152 是完整的minion_id c)、-E 正则表达式匹配 如,salt -E 'pre[1-7]' test.ping 会匹配pre1,pre2..pre7,并且匹配到左右minion_id 里面含有1-7的,如pre-11,pre7也会匹配到,如果只匹配1-7可使用参照下面 如,salt -E ^pre[1-7]$ test.ping或者 salt pre[1-7] test.ping d)、-C 混合模式,里面可以既有正则表达式也有列表等 salt -C "minion_* or test_minion" test.ping 匹配所有minion开头,或者test_minion id的 e)、分组,需要-N指定,其中组名就是上面/etc/salt/master.d/groups.conf文件里面配置的 配置信息。如,salt -N apache test.ping 2、常用模块 然后是模块,主要介绍state,cmd,cp模块 注:想了解某个模块的功能或者具体参数可以 salt \* sys.doc [模块名,如cmd] a)、cmd模块 salt '*' cmd.run "echo $HOSTNAME" 这里可以远程执行shell命令,执行结果会返回 b)、文件上传与下载 salt "minion_152" cp.get_file salt://files/test.txt /tmp/test.txt 将/srv/salt/files/test.txt 推送到minion_152 /tmp/下也叫test.txt 到minion_152 tmp目录下查看 同理可以通过 cp.push从minion上下载文件 需要修改master中的 file_recv: True salt "minion_152" cp.push /etc/fstab #默认下到本地 /var/cache/salt/master/minions/minion-id/files目录 其他的模块主参考官方文档。这里不再多说。 本文转自 dyc2005 51CTO博客,原文链接:http://blog.51cto.com/dyc2005/1967147,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android]Android开发入门之HelloWorld

引言:在做Unity开发的时候,发现这么个问题,虽然Unity是跨平台的,能够进行Android,IOS,Web,PC等开发,但如果要实现一些稍微系统层的东西,还是需要通过通信,调用原系统的接口(自定义的接口)来进行开发的,所以这还是需要了解其他平台原生态的开发的,之前我Web,IOS开发有了一定了解,最近要实现一个移动平台的二维码扫描功能,由于IOS我在现有资源的情况下,不能进行真机调试,但Android平台开发我又不熟悉,所以感觉很是头疼,于是就下定决心还是要了解一下原生态的Android开发,求人不如靠己,求人只能是暂时的,再有耐心的人都经过不起你的反复的问,他人也有他人的工作! 学习一门新的技术,都是从HelloWorld开始!这个是众所周知的,输入HelloWorld也就是进入了该开发的大门!下面我就写一下学习心得! 之前我一直从事的是Visual Stdio软件下的开发,无论是cocos2dx还是.net,Unity3d,都离不开VS,感觉微软最成功的不仅仅是Windows操作系统,还有一个就是Visual Stdio集成开发环境,我之前一直没有触碰与java相关的开发方向,就是因为习惯使用了VS,并且已经爱上它了,就不习惯Eclipse开发环境,java开发的程序员或许也会有这感觉,习惯上了Eclipse开发环境也就独爱它一样。现在由于不得已还是要学学Android开发,所以还是渐渐习惯用Eclipse吧,Eclipse与其他两大集成开发环境(Xcode,VS2010)有明显不同的就是配置繁琐,不耐心的程序员,或许就已经卡在配置的路上了,但不管怎样,耐心、细心、责任心是程序员必备的素质!这里配置Android开发环境就不介绍了,自己Baidu。接下来就是从HelloWorld创建开始! 一、重要的调试工具adb的介绍 adb(android debug bridge)android调试桥 打开Android SDK目录,介绍一下重要的adb工具,内部tcp调试桥,会通过socket,模拟器来执行指定的操作 。adb这工具比较重要,我们常会用它来调试,我们可以添加在环境变量,配置操作:我的电脑->右击->属性->高级->环境变量 然后在cmd中就可以使用adb工具了 adb基本操作 a)将本地文件拷贝到手机中 adb push [源文件] [目标文件] adb push 1.txt /mnt/sdcard/1.txt b)将手机文件拷贝到本地 adb pull [源文件] [本地] adb pull /data/app/Apidemos.apk C:\demo.apk c)杀死某一进程 adb kill start-server d)将桌面某一应用(apk)安装到手机模拟器上 adb install demo.apk e)卸载某一应用 adb uninstall 包名(进程名) adb uninstall com.example.android.apis 其实豌豆荚 QQ手机关机 91手机助手这些应用程序就是将这些命令封装了一下,然后执行了相应操作 f)查看adb的版本 adb version (许多莫名其妙的问题就是可能因为adb的版本原因导致的) g)查看当前所有连接上来的设备信息 adb devices(如果是真机连接上,也会显示真机的名字) h)来到模拟器或者真机的控制台 adb shell Android手机其实是Linux操作系统的控制台 ls查看目录信息 ps就可以查看当前正在运行的进程信息 kill就可以杀死某一进程 #kill 127(pid进程号) 这些都是linux的命令了,就不详细介绍了! ctrl+f11切换屏幕横竖屏 二、HelloWorld开发 1.基本创建 File->New->Android Application Project 生成的目录 2.生成的目录解析 project.properties 文件夹 指定开发使用的android.jar的版本 android-17 Android 4.2.2 android-8 Android 2.2 API级别与NDK的对应关系如下: Code name Version API level (no code name) 1.0 API level 1 (no code name) 1.1 API level 2 Cupcake 1.5 API level 3, NDK 1 Donut 1.6 API level 4, NDK 2 Eclair 2.0 API level 5 Eclair 2.0.1 API level 6 Eclair 2.1 API level 7, NDK 3 Froyo 2.2.x API level 8, NDK 4 Gingerbread 2.3 - 2.3.2 API level 9, NDK 5 Gingerbread 2.3.3 - 2.3.7 API level 10 Honeycomb 3.0 API level 11 Honeycomb 3.1 API level 12, NDK 6 Honeycomb 3.2.x API level 13 IceCreamSandwich 4.0.1 - 4.0.2 API level 14, NDK 7 IceCreamSandwich 4.0.3 API level 15 AndroidManifest.xml 将我们应用到的信息给注册到Android系统上,相当于注册表 注册了包名、版本号 <activity>节点是我们应用程序的主界面 修改图标,添加节点信息 在res文件加下新建drawable文件夹作为存放图片的文件夹,放一个5.png的图标 android:icon = "@drawable/5" res文件夹 values文件夹下面的strings.xml是配置app的名字已经启动文本,这里修改一下app的名字 layout文件夹下的activity_main.xml是界面布局的文件,点击GraphicalLayout就是界面的预览, 点击activity_main.xml修改文本信息,改成“Android开发,我要征服你” 所有res文件下的资源配置信息,我们在gen目录包下面都会有一个R.java,这个是由aadt工具自动生成的,都是以一个int类型的引用形式存在的,我们在res/values/strings.xml下添加一个节点<string name= "myname">丁小未</string> 然后去看R文件,会发现自动生成了一个 public static final int myname=0x7f050003;与之对应的引用 R文件的作用:为了方便程序中重复的使用定义的资源文件,做到程序跟资源相分离,然后我们来解释一下之前写的android:icon="@drawable/5",这样写的道理 @代表R文件,drawable就是代表R类的内部类,5是指内部类里面的5所指向的地址的图标 总而言之就是res资源文件R文件都会自动生成一个int类型的节点信息来同意管理资源 最后介绍最关键的src(源码文件夹)/MainActivity文件,Android开发每一个Activity都是对应这一个与之对应的界面 类比:做jsp开发的时候,.jsp文件都是对应着一个用户可以见到的网页;.net开发中,.aspx文件也是用户可以见到的动态网页,这里采用了MVC的这种模式,是采用这种Activity类来实现用户可见的界面 双击MainActivity.java文件,看到onCreate方法,是在应用第一次启动的时候执行的方法,其中有这么一段代码 setContentView(R.layout.activity_main);这就是设置activity的布局,我们可以自定义布局,拖动一些控件到activity上 布局的就是R文件下layout节点下activity_main的资源,对应于res/layout/activity_main.xml文件,Android开发最重要的就是这个R文件 常见错误: 1.例如如果注册表文件 AndroidManifest.xml中android:name写错了,系统启动的时候会报一个加载出错,因为系统在启动的时候首先就是去访问该注册表的文件, 由于清单文件配置出错,系统找不到与之对应的activity 2.AndroidManifest.xml中 <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> 这段配置文件的作用:在luncher程序里面生成一个应用程序的图标,如果我们删了,重新启动,log日志会显示安装成功HelloWorlddown,但我们点击应用图标却会提示我们没有安装应用程序! 更多精彩教程请关注我的微博 本文转蓬莱仙羽 51CTO博客,原文链接:http://blog.51cto.com/dingxiaowei/1392470,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-Xcode入门ObjC程序

元旦三天假跟妹子冷战一天半,剩下的半天觉得无聊,可以写点东西,折腾了下xCode 6.1,虽然iPhone6比较丑,但是不影响IOS在高端机上面的地位,ObjC是扩充C的面向对象编程语言。主要使用于Mac OS X和GNUStep这两个使用OpenStep标准的系统,在NeXTSTEP和OpenStep中它更是基本语言。ObjC可以在GCC以及Clang运作的系统上编写和编译,因GCC与Clang含Objective-C的编译器。1980年代初布莱德·确斯(Brad Cox)在其公司Stepstone发明Objective-C。算起来也有30多年的历史了,真正火起来还是因为IOS,成为编写苹果家族移动领域的神器。开始正题吧: OC项目 1.启动页面 2.简单的项目命令行项目,类似于vs中的控制台 3.命名项目名称 4.项目保存路径 5.项目结构,运行项目及其结果 调整字体 默认的字体很小,个人看的很不习惯,启动xCode之后,最上面xCode下有Preference,之后可以看到以下页面: 这个时候可以看到很多选项,最简单暴力一点就是全部command+a全选,全部调整一下,调整字体页面: 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4198895.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

spark 入门及集群环境搭建

软件环境: VMware workstation 11.0 linux :CentOS 6.7 hadoop-2.7.3 jdk-1.0.7_67 spark-2.1.0-bin-hadoop2.7/ 安装虚拟机和jdk就不再此赘述。 直接讲解安装hadoop和spark的安装。 一。下载hadoop源码包。点击此处下载:http://hadoop.apache.org/ 1.下载后解压到指定的目录下。 tar -zxvf hadoop-2.7.3.tar.gz -C /usr/hadoop 2.解压后进入目录 cd /usr/hadoop/hadoop-2.7.3 3.修改配置文件: 进入到cd /hadoop-2.7.3/etc/hadoop下需要修改几个配置文件 1> cpetc/hadoop/hadoop-env.sh.template.hadoop-env.sh cpetc/hadoop/hdfs-site.xml.templete hdfs-site.xml cpetc/hadoop/core-site.templete core-site.xml cp etc/hadoop/mapred-env.sh.templete mapred-env.sh cp etc/hadoop/mapred-site.templete mapred-site.sh cp etc/hadoop/slaves.templete slaves cp etc/yarn-env.sh.templete yarn-env.sh cp etc/yarn-site.xml.templete yarn-site.xml 注意: 一般修改系统配置文件时最好做一个备份或者复制后修改,就像这样的。 hadoop-env.sh 配置文件的内容 #Thejavaimplementationtouse. exportJAVA_HOME=/opt/modules/jdk1.7.0_67/ 这是需要修改为自己机器安装的jdk的位置。其他文件内容不需要修改。 hdfs-site.xml <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.block.size</name> <value>134217728</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/home/hadoopdata/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/home/hadoopdata/dfs/data</value> </property> <property> <name>fs.checkpoint.dir</name> <value>/home/hadoopdata/checkpoint/dfs/cname</value> </property> <property> <name>fs.checkpoint.edits.dir</name> <value>/home/hadoopdata/checkpoint/dfs/cname</value> </property> <property> <name>dfs.http.address</name> <value>master:50070</value> </property> <property> <name>dfs.secondary.http.address</name> <value>slave1:50090</value> </property> <property> <name>dfs.webhdfs.enabled</name> <value>true</value> </property> <property> <name>dfs.permissions</name> <value>true</value> </property> </configuration> 3> core-site.xml <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://master:8020</value> </property> <property> <name>io.file.buffer.size</name> <value>4096</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/modules/hadoop-2.7.3/data/tmp</value> </property> </configuration> 4> mapred-env.sh exportJAVA_HOME=/usr/local/java/jdk1.7.0_67/ 修改为自己电脑的jdk路径。 5> mapred-site.xml <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> <final>true</final> </property> <property> <name>mapreduce.jobhistory.address</name> <value>master:10020</value> </property> <property> <name>mapreduce.jobhistory.webapp.address</name> <value>master:19888</value> </property> <property> <name>mapreduce.job.ubertask.enable</name> <value>true</value> </property> <property> <!-- 配置map任务的主节点 运行在哪台节点--> <name>mapred.job.tracker</name> <value>master:9001</value> </property> 6> slaves 设置需要几个节点运行 master slave1 slave2 7> yarn-env.sh JAVA=$JAVA_HOME/bin/java 引用jdk的路径 8> yarn-site.xml <property> <name>yarn.resourcemanager.hostname</name> <value>salve2 </value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.address</name> <value>slave2:8032</value> </property> <property> <name>yarn.resourcemanager.scheduler.address</name> <value>slave2:8030</value> </property> <property> <name>yarn.resourcemanager.resource-tracker.address</name> <value>slave2:8031</value> </property> <property> <name>yarn.resourcemanager.admin.address</name> <value>slave2:8033</value> </property> <property> <name>yarn.resourcemanager.webapp.address</name> <value>slave2:8088</value> </property> <property> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <property> <name>yarn.nodemanager.remote-app-log-dir</name> <value>/opt/modules/hadoop-2.7.3/tmp/logs</value> </property> 注意: 修改完配置后,需要将hadoop分发到其他节点。 slave1和slave2. scp -r /usr/hadoop/hadoop-2.7.3 root@slave1:/usr/hadoop scp -r /usr/hadoop/hadoop-2.7.3 root@slave2:/usr/hadoop 然后需要修改环境变量文件。可以修改当前用户的 环境变量文件,就是~./bash_rc 或全局变量文件 /etc/profile export JAVA_HOME=/usr/local/jdk-1.7.0_67 export PATH=:PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin: 保存 :wq; 然后可以把环境变量文件发送给其他节点。 二. 格式化namenode节点 hadoop namenode -format 会看到一堆输出信息。然后会提示namenode 格式化成功的提示。 三。启动集群. 可以全部启动,也可以单独 启动。 hadoop 安装路径下有个sbin 目录,下是存放的是系统的启动脚本。 全部启动: start-all.sh 单独启动节点: hadoop-daemon.sh start namenode/datanode xxx. 启动后用jps查看进程。 本文转自 ChinaUnicom110 51CTO博客,原文链接:http://blog.51cto.com/xingyue2011/1947302

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册